| 1 | r""" |
| 2 | Generate interpreters for fast_callable |
| 3 | |
| 4 | AUTHORS: |
| 5 | |
| 6 | - Carl Witty |
| 7 | |
| 8 | This file is part of the Sage support for "planned" computations; |
| 9 | that is, computations that are separated into a planning stage and |
| 10 | a plan-execution stage. Here, we generate fast interpreters for plan |
| 11 | executions. |
| 12 | |
| 13 | There are at least two kinds of computations that are often planned in |
| 14 | this fashion. First is arithmetic expression evaluation, where we |
| 15 | take an arbitrary user-specified arithmetic expression and compile it |
| 16 | into a bytecode form for fast interpretation. Second is things like |
| 17 | FFTs and large multiplications, where large problems are split into |
| 18 | multiple smaller problems... we can do the logical "splitting" for a |
| 19 | given size only once, producing a plan which can be reused as often as |
| 20 | we want for different problems of the same size. Currently only |
| 21 | arithmetic expression evaluation is implemented, but other kinds of |
| 22 | planned computations should be easy to add. |
| 23 | |
| 24 | Typically, for arithmetic expressions, we want the storage of |
| 25 | intermediate results to be handled automatically (on a stack); for |
| 26 | FFTs/multiplications/etc., the planner will keep track of intermediate |
| 27 | results itself. |
| 28 | |
| 29 | For arithmetic expression evaluation, we want to have lots of |
| 30 | interpreters (at least one, and possibly several, per |
| 31 | specially-handled type). Also, for any given type, we have many |
| 32 | possible variants of instruction encoding, etc.; some of these could |
| 33 | be handled with conditional compilation, but some are more |
| 34 | complicated. So we end up writing an interpreter generator. |
| 35 | |
| 36 | We want to share as much code as possible across all of these |
| 37 | interpreters, while still maintaining the freedom to make drastic |
| 38 | changes in the interpretation strategy (which may change the |
| 39 | generated code, the calling convention for the interpreter, etc.) |
| 40 | |
| 41 | To make this work, the interpreter back-end is divided into three |
| 42 | parts: |
| 43 | |
| 44 | 1. The interpreter itself, in C or C++. |
| 45 | |
| 46 | 2. The wrapper, which is a Cython object holding the |
| 47 | constants, code, etc., and which actually calls the interpreter. |
| 48 | |
| 49 | 3. The code generator. |
| 50 | |
| 51 | We generate parts 1 and 2. The code generator is table-driven, |
| 52 | and we generate the tables for the code generator. |
| 53 | |
| 54 | There are a lot of techniques for fast interpreters that we do not yet |
| 55 | use; hopefully at least some of these will eventually be implemented: |
| 56 | |
| 57 | - using gcc's "labels as values" extension where available |
| 58 | |
| 59 | - top-of-stack caching |
| 60 | |
| 61 | - superinstructions and/or superoperators |
| 62 | |
| 63 | - static stack caching |
| 64 | |
| 65 | - context threading/subrouting threading |
| 66 | |
| 67 | - selective inlining/dynamic superinstructions |
| 68 | |
| 69 | - automatic replication |
| 70 | |
| 71 | Interpreters may be stack-based or register-based. Recent research |
| 72 | suggests that register-based interpreters are better, but the |
| 73 | researchers are investigating interpreters for entire programming |
| 74 | languages, rather than interpreters for expressions. I suspect |
| 75 | that stack-based expression interpreters may be better. However, |
| 76 | we'll implement both varieties and see what's best. |
| 77 | |
| 78 | The relative costs of stack- and register-based interpreters will |
| 79 | depend on the costs of moving values. For complicated types (like |
| 80 | mpz_t), a register-based interpreter will quite likely be better, |
| 81 | since it will avoid moving values. |
| 82 | |
| 83 | We will NOT support any sort of storage of bytecode; instead, the |
| 84 | code must be re-generated from expression trees in every Sage run. |
| 85 | This means that we can trivially experiment with different styles of |
| 86 | interpreter, or even use quite different interpreters depending on |
| 87 | the architecture, without having to worry about forward and backward |
| 88 | compatibility. |
| 89 | """ |
| 90 | #***************************************************************************** |
| 91 | # Copyright (C) 2009 Carl Witty <Carl.Witty@gmail.com> |
| 92 | # |
| 93 | # Distributed under the terms of the GNU General Public License (GPL) |
| 94 | # http://www.gnu.org/licenses/ |
| 95 | #***************************************************************************** |
| 96 | |
| 97 | from __future__ import with_statement |
| 98 | |
| 99 | import os |
| 100 | import re |
| 101 | from jinja import Environment |
| 102 | from jinja.datastructure import ComplainingUndefined |
| 103 | from collections import defaultdict |
| 104 | from distutils.extension import Extension |
| 105 | |
| 106 | ############################## |
| 107 | # This module is used during the Sage buld process, so it should not |
| 108 | # use any other Sage modules. (In particular, it MUST NOT use any |
| 109 | # Cython modules -- they won't be built yet!) |
| 110 | # Also, we have some trivial dependency tracking, where we don't |
| 111 | # rebuild the interpreters if this file hasn't changed; if |
| 112 | # interpreter configuation is split out into a separate file, |
| 113 | # that will have to be changed. |
| 114 | ############################## |
| 115 | |
| 116 | |
| 117 | # We share a single jinja environment among all templating in this file. |
| 118 | # We use trim_blocks=True (which means that we ignore white space after |
| 119 | # "%}" jinja command endings), and set undefined_singleton to complain |
| 120 | # if we use an undefined variable. |
| 121 | jinja_env = Environment(trim_blocks=True, |
| 122 | undefined_singleton=ComplainingUndefined) |
| 123 | # Allow 'i' as a shorter alias for the built-in 'indent' filter. |
| 124 | jinja_env.filters['i'] = jinja_env.filters['indent'] |
| 125 | |
| 126 | def indent_lines(n, text): |
| 127 | r""" |
| 128 | INPUTS: |
| 129 | n -- indentation amount |
| 130 | text -- text to indent |
| 131 | |
| 132 | Indents each line in text by n spaces. |
| 133 | |
| 134 | EXAMPLES: |
| 135 | sage: from sage.ext.gen_interpreters import indent_lines |
| 136 | sage: indent_lines(3, "foo") |
| 137 | ' foo' |
| 138 | sage: indent_lines(3, "foo\nbar") |
| 139 | ' foo\n bar' |
| 140 | sage: indent_lines(3, "foo\nbar\n") |
| 141 | ' foo\n bar\n' |
| 142 | """ |
| 143 | lines = text.splitlines(True) |
| 144 | spaces = ' ' * n |
| 145 | return ''.join(spaces + line for line in lines) |
| 146 | |
| 147 | def je(template, **kwargs): |
| 148 | r""" |
| 149 | A convenience method for creating strings with Jinja templates. |
| 150 | The name je stands for "Jinja evaluate". |
| 151 | |
| 152 | The first argument is the template string; remaining keyword |
| 153 | arguments define Jinja variables. |
| 154 | |
| 155 | If the first character in the template string is a newline, it is |
| 156 | removed (this feature is useful when using multi-line templates defined |
| 157 | with triple-quoted strings -- the first line doesn't have to be on |
| 158 | the same line as the quotes, which would screw up the indentation). |
| 159 | |
| 160 | (This is very inefficient, because it recompiles the Jinja |
| 161 | template on each call; don't use it in situations where |
| 162 | performance is important.) |
| 163 | |
| 164 | EXAMPLES: |
| 165 | sage: from sage.ext.gen_interpreters import je |
| 166 | sage: je("{{ a }} > {{ b }} * {{ c }}", a='"a suffusion of yellow"', b=3, c=7) |
| 167 | u'"a suffusion of yellow" > 3 * 7' |
| 168 | """ |
| 169 | if len(template) > 0 and template[0] == '\n': |
| 170 | template = template[1:] |
| 171 | |
| 172 | # It looks like Jinja automatically removes one trailing newline? |
| 173 | if len(template) > 0 and template[-1] == '\n': |
| 174 | template = template + '\n' |
| 175 | |
| 176 | tmpl = jinja_env.from_string(template) |
| 177 | return tmpl.render(kwargs) |
| 178 | |
| 179 | class StorageType(object): |
| 180 | r""" |
| 181 | A StorageType specifies the C types used to deal with values of a |
| 182 | given type. |
| 183 | |
| 184 | We currently support three categories of types. |
| 185 | |
| 186 | First are the "simple" types. These are types where: the |
| 187 | representation is small, functions expect arguments to be passed |
| 188 | by value, and the C/C++ assignment operator works. This would |
| 189 | include built-in C types (long, float, etc.) and small structs |
| 190 | (like gsl_complex). |
| 191 | |
| 192 | Second is 'PyObject*'. This is just like a simple type, except |
| 193 | that we have to incref/decref at appropriate places. |
| 194 | |
| 195 | Third is "auto-reference" types. This is how |
| 196 | GMP/MPIR/MPFR/MPFI/FLINT types work. For these types, functions |
| 197 | expect arguments to be passed by reference, and the C assignment |
| 198 | operator does not do what we want. In addition, they take |
| 199 | advantage of a quirk in C (where arrays are automatically |
| 200 | converted to pointers) to automatically pass arguments by |
| 201 | reference. |
| 202 | |
| 203 | Support for further categories would not be difficult to add (such |
| 204 | as reference-counted types other than PyObject*, or |
| 205 | pass-by-reference types that don't use the GMP auto-reference |
| 206 | trick), if we ever run across a use for them. |
| 207 | """ |
| 208 | |
| 209 | def __init__(self): |
| 210 | r""" |
| 211 | Initialize an instance of StorageType. |
| 212 | |
| 213 | This sets several properties: |
| 214 | |
| 215 | class_member_declarations: |
| 216 | A string giving variable declarations that must be members of any |
| 217 | wrapper class using this type. |
| 218 | |
| 219 | class_member_initializations: |
| 220 | A string initializing the class_member_declarations; will be |
| 221 | inserted into the __init__ method of any wrapper class using this |
| 222 | type. |
| 223 | |
| 224 | local_declarations: |
| 225 | A string giving variable declarations that must be local variables |
| 226 | in Cython methods using this storage type. |
| 227 | |
| 228 | EXAMPLES: |
| 229 | sage: from sage.ext.gen_interpreters import * |
| 230 | sage: ty_double.class_member_declarations |
| 231 | '' |
| 232 | sage: ty_double.class_member_initializations |
| 233 | '' |
| 234 | sage: ty_double.local_declarations |
| 235 | '' |
| 236 | sage: ty_mpfr.class_member_declarations |
| 237 | 'cdef RealField domain\n' |
| 238 | sage: ty_mpfr.class_member_initializations |
| 239 | "self.domain = args['domain']\n" |
| 240 | sage: ty_mpfr.local_declarations |
| 241 | 'cdef RealNumber rn\n' |
| 242 | """ |
| 243 | self.class_member_declarations = '' |
| 244 | self.class_member_initializations = '' |
| 245 | self.local_declarations = '' |
| 246 | |
| 247 | def cheap_copies(self): |
| 248 | r""" |
| 249 | Returns True or False, depending on whether this StorageType |
| 250 | supports cheap copies -- whether it is cheap to copy values of |
| 251 | this type from one location to another. This is true for |
| 252 | primitive types, and for types like PyObject* (where you're only |
| 253 | copying a pointer, and possibly changing some reference counts). |
| 254 | It is false for types like mpz_t and mpfr_t, where copying values |
| 255 | can involve arbitrarily much work (including memory allocation). |
| 256 | |
| 257 | The practical effect is that if cheap_copies is True, |
| 258 | instructions with outputs of this type write the results into |
| 259 | local variables, and the results are then copied to their |
| 260 | final locations. If cheap_copies is False, then the addresses |
| 261 | of output locations are passed into the instruction and the |
| 262 | instruction writes outputs directly in the final location. |
| 263 | |
| 264 | EXAMPLES: |
| 265 | sage: from sage.ext.gen_interpreters import * |
| 266 | sage: ty_double.cheap_copies() |
| 267 | True |
| 268 | sage: ty_python.cheap_copies() |
| 269 | True |
| 270 | sage: ty_mpfr.cheap_copies() |
| 271 | False |
| 272 | """ |
| 273 | return False |
| 274 | |
| 275 | def python_refcounted(self): |
| 276 | r""" |
| 277 | Says whether this storage type is a Python type, so we need to |
| 278 | use INCREF/DECREF. |
| 279 | |
| 280 | (If we needed to support any non-Python refcounted types, it |
| 281 | might be better to make this object-oriented and have methods |
| 282 | like "generate an incref" and "generate a decref". But as |
| 283 | long as we only support Python, this way is probably simpler.) |
| 284 | |
| 285 | EXAMPLES: |
| 286 | sage: from sage.ext.gen_interpreters import * |
| 287 | sage: ty_double.python_refcounted() |
| 288 | False |
| 289 | sage: ty_python.python_refcounted() |
| 290 | True |
| 291 | """ |
| 292 | return False |
| 293 | |
| 294 | def cython_decl_type(self): |
| 295 | r""" |
| 296 | Gives the Cython type for a single value of this type (as a string). |
| 297 | |
| 298 | EXAMPLES: |
| 299 | sage: from sage.ext.gen_interpreters import * |
| 300 | sage: ty_double.cython_decl_type() |
| 301 | 'double' |
| 302 | sage: ty_python.cython_decl_type() |
| 303 | 'object' |
| 304 | sage: ty_mpfr.cython_decl_type() |
| 305 | 'mpfr_t' |
| 306 | """ |
| 307 | return self.c_decl_type() |
| 308 | |
| 309 | def cython_array_type(self): |
| 310 | r""" |
| 311 | Gives the Cython type for referring to an array of values of |
| 312 | this type (as a string). |
| 313 | |
| 314 | EXAMPLES: |
| 315 | sage: from sage.ext.gen_interpreters import * |
| 316 | sage: ty_double.cython_array_type() |
| 317 | 'double*' |
| 318 | sage: ty_python.cython_array_type() |
| 319 | 'PyObject**' |
| 320 | sage: ty_mpfr.cython_array_type() |
| 321 | 'mpfr_t*' |
| 322 | """ |
| 323 | return self.c_ptr_type() |
| 324 | |
| 325 | def needs_cython_init_clear(self): |
| 326 | r""" |
| 327 | Says whether values/arrays of this type need to be initialized |
| 328 | before use and cleared before the underlying memory is freed. |
| 329 | |
| 330 | (We could remove this method, always call .cython_init() to |
| 331 | generate initialization code, and just let .cython_init() |
| 332 | generate empty code if no initialization is required; that would |
| 333 | generate empty loops, which are ugly and potentially might not |
| 334 | be optimized away.) |
| 335 | |
| 336 | EXAMPLES: |
| 337 | sage: from sage.ext.gen_interpreters import * |
| 338 | sage: ty_double.needs_cython_init_clear() |
| 339 | False |
| 340 | sage: ty_mpfr.needs_cython_init_clear() |
| 341 | True |
| 342 | sage: ty_python.needs_cython_init_clear() |
| 343 | True |
| 344 | """ |
| 345 | return False |
| 346 | |
| 347 | def c_decl_type(self): |
| 348 | r""" |
| 349 | Gives the C type for a single value of this type (as a string). |
| 350 | |
| 351 | EXAMPLES: |
| 352 | sage: from sage.ext.gen_interpreters import * |
| 353 | sage: ty_double.c_decl_type() |
| 354 | 'double' |
| 355 | sage: ty_python.c_decl_type() |
| 356 | 'PyObject*' |
| 357 | sage: ty_mpfr.c_decl_type() |
| 358 | 'mpfr_t' |
| 359 | """ |
| 360 | raise NotImplementedError |
| 361 | |
| 362 | def c_ptr_type(self): |
| 363 | r""" |
| 364 | Gives the C type for a pointer to this type (as a reference to |
| 365 | either a single value or an array) (as a string). |
| 366 | |
| 367 | EXAMPLES: |
| 368 | sage: from sage.ext.gen_interpreters import * |
| 369 | sage: ty_double.c_ptr_type() |
| 370 | 'double*' |
| 371 | sage: ty_python.c_ptr_type() |
| 372 | 'PyObject**' |
| 373 | sage: ty_mpfr.c_ptr_type() |
| 374 | 'mpfr_t*' |
| 375 | """ |
| 376 | return self.c_decl_type() + '*' |
| 377 | |
| 378 | def c_local_type(self): |
| 379 | r""" |
| 380 | Gives the C type used for a value of this type inside an |
| 381 | instruction. For assignable/cheap_copy types, this is the |
| 382 | same as c_decl_type; for auto-reference types, this is the |
| 383 | pointer type. |
| 384 | |
| 385 | EXAMPLES: |
| 386 | sage: from sage.ext.gen_interpreters import * |
| 387 | sage: ty_double.c_local_type() |
| 388 | 'double' |
| 389 | sage: ty_python.c_local_type() |
| 390 | 'PyObject*' |
| 391 | sage: ty_mpfr.c_local_type() |
| 392 | 'mpfr_ptr' |
| 393 | """ |
| 394 | raise NotImplementedError |
| 395 | |
| 396 | def assign_c_from_py(self, c, py): |
| 397 | r""" |
| 398 | Given a Cython variable/array reference/etc. of this storage type, |
| 399 | and a Python expression, generate code to assign to the Cython |
| 400 | variable from the Python expression. |
| 401 | |
| 402 | EXAMPLES: |
| 403 | sage: from sage.ext.gen_interpreters import * |
| 404 | sage: ty_double.assign_c_from_py('foo', 'bar') |
| 405 | u'foo = bar' |
| 406 | sage: ty_python.assign_c_from_py('foo[i]', 'bar[j]') |
| 407 | u'foo[i] = <PyObject *>bar[j]; Py_INCREF(foo[i])' |
| 408 | sage: ty_mpfr.assign_c_from_py('foo', 'bar') |
| 409 | u'rn = self.domain(bar)\nmpfr_set(foo, rn.value, GMP_RNDN)' |
| 410 | """ |
| 411 | return je("{{ c }} = {{ py }}", c=c, py=py) |
| 412 | |
| 413 | def declare_chunk_class_members(self, name): |
| 414 | r""" |
| 415 | Returns a string giving the declarations of the class members |
| 416 | in a wrapper class for a memory chunk with this storage type |
| 417 | and the given name. |
| 418 | |
| 419 | EXAMPLES: |
| 420 | sage: from sage.ext.gen_interpreters import * |
| 421 | sage: ty_mpfr.declare_chunk_class_members('args') |
| 422 | u' cdef int _n_args\n cdef mpfr_t* _args\n' |
| 423 | """ |
| 424 | return je(""" |
| 425 | {# XXX Variables here (and everywhere, really) should actually be Py_ssize_t #} |
| 426 | cdef int _n_{{ name }} |
| 427 | cdef {{ self.cython_array_type() }} _{{ name }} |
| 428 | """, self=self, name=name) |
| 429 | |
| 430 | def alloc_chunk_data(self, name, len): |
| 431 | r""" |
| 432 | Returns a string allocating the memory for the class members for |
| 433 | a memory chunk with this storage type and the given name. |
| 434 | |
| 435 | EXAMPLES: |
| 436 | sage: from sage.ext.gen_interpreters import * |
| 437 | sage: print ty_mpfr.alloc_chunk_data('args', 'MY_LENGTH') |
| 438 | self._n_args = MY_LENGTH |
| 439 | self._args = <mpfr_t*>sage_malloc(sizeof(mpfr_t) * MY_LENGTH) |
| 440 | if self._args == NULL: raise MemoryError |
| 441 | for i in range(MY_LENGTH): |
| 442 | mpfr_init2(self._args[i], self.domain.prec()) |
| 443 | <BLANKLINE> |
| 444 | """ |
| 445 | return je(""" |
| 446 | self._n_{{ name }} = {{ len }} |
| 447 | self._{{ name }} = <{{ self.c_ptr_type() }}>sage_malloc(sizeof({{ self.c_decl_type() }}) * {{ len }}) |
| 448 | if self._{{ name }} == NULL: raise MemoryError |
| 449 | {% if self.needs_cython_init_clear() %} |
| 450 | for i in range({{ len }}): |
| 451 | {{ self.cython_init('self._%s[i]' % name) }} |
| 452 | {% endif %} |
| 453 | """, self=self, name=name, len=len) |
| 454 | |
| 455 | def dealloc_chunk_data(self, name): |
| 456 | r""" |
| 457 | Returns a string to be put in the __dealloc__ method of a |
| 458 | wrapper class using a memory chunk with this storage type, to |
| 459 | deallocate the corresponding class members. |
| 460 | |
| 461 | EXAMPLES: |
| 462 | sage: from sage.ext.gen_interpreters import * |
| 463 | sage: print ty_double.dealloc_chunk_data('args') |
| 464 | if self._args: |
| 465 | sage_free(self._args) |
| 466 | <BLANKLINE> |
| 467 | sage: print ty_mpfr.dealloc_chunk_data('constants') |
| 468 | if self._constants: |
| 469 | for i in range(self._n_constants): |
| 470 | mpfr_clear(self._constants[i]) |
| 471 | sage_free(self._constants) |
| 472 | <BLANKLINE> |
| 473 | """ |
| 474 | return je(""" |
| 475 | if self._{{ name }}: |
| 476 | {% if self.needs_cython_init_clear() %} |
| 477 | for i in range(self._n_{{ name }}): |
| 478 | {{ self.cython_clear('self._%s[i]' % name) }} |
| 479 | {% endif %} |
| 480 | sage_free(self._{{ name }}) |
| 481 | """, self=self, name=name) |
| 482 | |
| 483 | class StorageTypeAssignable(StorageType): |
| 484 | r""" |
| 485 | StorageTypeAssignable is a subtype of StorageType that deals with |
| 486 | types with cheap copies, like primitive types and PyObject*. |
| 487 | """ |
| 488 | |
| 489 | def __init__(self, ty): |
| 490 | r""" |
| 491 | Initializes the property type (the C/Cython name for this type), |
| 492 | as well as the properties described in the documentation for |
| 493 | StorageType.__init__. |
| 494 | |
| 495 | EXAMPLES: |
| 496 | sage: from sage.ext.gen_interpreters import * |
| 497 | sage: ty_double.class_member_declarations |
| 498 | '' |
| 499 | sage: ty_double.class_member_initializations |
| 500 | '' |
| 501 | sage: ty_double.local_declarations |
| 502 | '' |
| 503 | sage: ty_double.type |
| 504 | 'double' |
| 505 | sage: ty_python.type |
| 506 | 'PyObject*' |
| 507 | """ |
| 508 | StorageType.__init__(self) |
| 509 | self.type = ty |
| 510 | |
| 511 | def cheap_copies(self): |
| 512 | r""" |
| 513 | Returns True or False, depending on whether this StorageType |
| 514 | supports cheap copies -- whether it is cheap to copy values of |
| 515 | this type from one location to another. (See StorageType.cheap_copies |
| 516 | for more on this property.) |
| 517 | |
| 518 | Since having cheap copies is essentially the definition of |
| 519 | StorageTypeAssignable, this always returns True. |
| 520 | |
| 521 | EXAMPLES: |
| 522 | sage: from sage.ext.gen_interpreters import * |
| 523 | sage: ty_double.cheap_copies() |
| 524 | True |
| 525 | sage: ty_python.cheap_copies() |
| 526 | True |
| 527 | """ |
| 528 | return True |
| 529 | |
| 530 | def c_decl_type(self): |
| 531 | r""" |
| 532 | Gives the C type for a single value of this type (as a string). |
| 533 | |
| 534 | EXAMPLES: |
| 535 | sage: from sage.ext.gen_interpreters import * |
| 536 | sage: ty_double.c_decl_type() |
| 537 | 'double' |
| 538 | sage: ty_python.c_decl_type() |
| 539 | 'PyObject*' |
| 540 | """ |
| 541 | return self.type |
| 542 | |
| 543 | def c_local_type(self): |
| 544 | r""" |
| 545 | Gives the C type used for a value of this type inside an |
| 546 | instruction. For assignable/cheap_copy types, this is the |
| 547 | same as c_decl_type; for auto-reference types, this is the |
| 548 | pointer type. |
| 549 | |
| 550 | EXAMPLES: |
| 551 | sage: from sage.ext.gen_interpreters import * |
| 552 | sage: ty_double.c_local_type() |
| 553 | 'double' |
| 554 | sage: ty_python.c_local_type() |
| 555 | 'PyObject*' |
| 556 | """ |
| 557 | return self.type |
| 558 | |
| 559 | class StorageTypeSimple(StorageTypeAssignable): |
| 560 | r""" |
| 561 | StorageTypeSimple is a subtype of StorageTypeAssignable that deals |
| 562 | with non-reference-counted types with cheap copies, like primitive |
| 563 | types. As of yet, it has no functionality differences from |
| 564 | StorageTypeAssignable. |
| 565 | """ |
| 566 | pass |
| 567 | |
| 568 | ty_int = StorageTypeSimple('int') |
| 569 | ty_double = StorageTypeSimple('double') |
| 570 | |
| 571 | class StorageTypePython(StorageTypeAssignable): |
| 572 | r""" |
| 573 | StorageTypePython is a subtype of StorageTypeAssignable that deals |
| 574 | with Python objects. |
| 575 | |
| 576 | Just allocating an array full of PyObject* leads to problems, |
| 577 | because the Python garbage collector must be able to get to every |
| 578 | Python object, and it wouldn't know how to get to these arrays. |
| 579 | So we allocate the array as a Python list, but then we immediately |
| 580 | pull the ob_item out of it and deal only with that from then on. |
| 581 | |
| 582 | We often leave these lists with NULL entries. This is safe for |
| 583 | the garbage collector and the deallocator, which is all we care |
| 584 | about; but it would be unsafe to provide Python-level access to |
| 585 | these lists. |
| 586 | |
| 587 | There is one special thing about StorageTypePython: memory that is |
| 588 | used by the interpreter as scratch space (for example, the stack) |
| 589 | must be cleared after each call (so we don't hold on to |
| 590 | potentially-large objects and waste memory). Since we have to do |
| 591 | this anyway, the interpreter gains a tiny bit of speed by assuming |
| 592 | that the scratch space is cleared on entry; for example, when |
| 593 | pushing a value onto the stack, it doesn't bother to XDECREF the |
| 594 | previous value because it's always NULL. |
| 595 | """ |
| 596 | |
| 597 | def __init__(self): |
| 598 | r""" |
| 599 | Initializes the properties described in the documentation |
| 600 | for StorageTypeAssignable.__init__. The type is always |
| 601 | 'PyObject*'. |
| 602 | |
| 603 | EXAMPLES: |
| 604 | sage: from sage.ext.gen_interpreters import * |
| 605 | sage: ty_python.class_member_declarations |
| 606 | '' |
| 607 | sage: ty_python.class_member_initializations |
| 608 | '' |
| 609 | sage: ty_python.local_declarations |
| 610 | '' |
| 611 | sage: ty_python.type |
| 612 | 'PyObject*' |
| 613 | """ |
| 614 | StorageTypeAssignable.__init__(self, 'PyObject*') |
| 615 | |
| 616 | def python_refcounted(self): |
| 617 | r""" |
| 618 | Says whether this storage type is a Python type, so we need to |
| 619 | use INCREF/DECREF. |
| 620 | |
| 621 | Returns True. |
| 622 | |
| 623 | EXAMPLES: |
| 624 | sage: from sage.ext.gen_interpreters import * |
| 625 | sage: ty_python.python_refcounted() |
| 626 | True |
| 627 | """ |
| 628 | return True |
| 629 | |
| 630 | def cython_decl_type(self): |
| 631 | r""" |
| 632 | Gives the Cython type for a single value of this type (as a string). |
| 633 | |
| 634 | EXAMPLES: |
| 635 | sage: from sage.ext.gen_interpreters import * |
| 636 | sage: ty_python.cython_decl_type() |
| 637 | 'object' |
| 638 | """ |
| 639 | return 'object' |
| 640 | |
| 641 | def declare_chunk_class_members(self, name): |
| 642 | r""" |
| 643 | Returns a string giving the declarations of the class members |
| 644 | in a wrapper class for a memory chunk with this storage type |
| 645 | and the given name. |
| 646 | |
| 647 | EXAMPLES: |
| 648 | sage: from sage.ext.gen_interpreters import * |
| 649 | sage: ty_python.declare_chunk_class_members('args') |
| 650 | u' cdef object _list_args\n cdef int _n_args\n cdef PyObject** _args\n' |
| 651 | """ |
| 652 | return je(""" |
| 653 | cdef object _list_{{ name }} |
| 654 | cdef int _n_{{ name }} |
| 655 | cdef {{ self.cython_array_type() }} _{{ name }} |
| 656 | """, self=self, name=name) |
| 657 | |
| 658 | def alloc_chunk_data(self, name, len): |
| 659 | r""" |
| 660 | Returns a string allocating the memory for the class members for |
| 661 | a memory chunk with this storage type and the given name. |
| 662 | |
| 663 | EXAMPLES: |
| 664 | sage: from sage.ext.gen_interpreters import * |
| 665 | sage: print ty_python.alloc_chunk_data('args', 'MY_LENGTH') |
| 666 | self._n_args = MY_LENGTH |
| 667 | self._list_args = PyList_New(self._n_args) |
| 668 | self._args = (<PyListObject *>self._list_args).ob_item |
| 669 | <BLANKLINE> |
| 670 | """ |
| 671 | return je(""" |
| 672 | self._n_{{ name }} = {{ len }} |
| 673 | self._list_{{ name }} = PyList_New(self._n_{{ name }}) |
| 674 | self._{{ name }} = (<PyListObject *>self._list_{{ name }}).ob_item |
| 675 | """, self=self, name=name, len=len) |
| 676 | |
| 677 | def dealloc_chunk_data(self, name): |
| 678 | r""" |
| 679 | Returns a string to be put in the __dealloc__ method of a |
| 680 | wrapper class using a memory chunk with this storage type, to |
| 681 | deallocate the corresponding class members. |
| 682 | |
| 683 | Our array was allocated as a Python list; this means we actually |
| 684 | don't need to do anything to deallocate it. |
| 685 | |
| 686 | EXAMPLES: |
| 687 | sage: from sage.ext.gen_interpreters import * |
| 688 | sage: ty_python.dealloc_chunk_data('args') |
| 689 | '' |
| 690 | """ |
| 691 | return '' |
| 692 | |
| 693 | def needs_cython_init_clear(self): |
| 694 | r""" |
| 695 | Says whether values/arrays of this type need to be initialized |
| 696 | before use and cleared before the underlying memory is freed. |
| 697 | |
| 698 | Returns True. |
| 699 | |
| 700 | EXAMPLES: |
| 701 | sage: from sage.ext.gen_interpreters import * |
| 702 | sage: ty_python.needs_cython_init_clear() |
| 703 | True |
| 704 | """ |
| 705 | return True |
| 706 | |
| 707 | def assign_c_from_py(self, c, py): |
| 708 | r""" |
| 709 | Given a Cython variable/array reference/etc. of this storage type, |
| 710 | and a Python expression, generate code to assign to the Cython |
| 711 | variable from the Python expression. |
| 712 | |
| 713 | EXAMPLES: |
| 714 | sage: from sage.ext.gen_interpreters import * |
| 715 | sage: ty_python.assign_c_from_py('foo[i]', 'bar[j]') |
| 716 | u'foo[i] = <PyObject *>bar[j]; Py_INCREF(foo[i])' |
| 717 | """ |
| 718 | return je("""{{ c }} = <PyObject *>{{ py }}; Py_INCREF({{ c }})""", |
| 719 | c=c, py=py) |
| 720 | |
| 721 | def cython_init(self, loc): |
| 722 | r""" |
| 723 | Generates code to initialize a variable (or array reference) |
| 724 | holding a PyObject*. Sets it to NULL. |
| 725 | |
| 726 | EXAMPLES: |
| 727 | sage: from sage.ext.gen_interpreters import * |
| 728 | sage: ty_python.cython_init('foo[i]') |
| 729 | u'foo[i] = NULL' |
| 730 | """ |
| 731 | return je("{{ loc }} = NULL", loc=loc) |
| 732 | |
| 733 | def cython_clear(self, loc): |
| 734 | r""" |
| 735 | Generates code to clear a variable (or array reference) holding |
| 736 | a PyObject*. |
| 737 | |
| 738 | EXAMPLES: |
| 739 | sage: from sage.ext.gen_interpreters import * |
| 740 | sage: ty_python.cython_clear('foo[i]') |
| 741 | u'Py_CLEAR(foo[i])' |
| 742 | """ |
| 743 | return je("Py_CLEAR({{ loc }})", loc=loc) |
| 744 | |
| 745 | ty_python = StorageTypePython() |
| 746 | |
| 747 | class StorageTypeAutoReference(StorageType): |
| 748 | r""" |
| 749 | StorageTypeAutoReference is a subtype of StorageType that deals with |
| 750 | types in the style of GMP/MPIR/MPFR/MPFI/FLINT, where copies are |
| 751 | not cheap, functions expect arguments to be passed by reference, |
| 752 | and the API takes advantage of the C quirk where arrays are |
| 753 | automatically converted to pointers to automatically pass |
| 754 | arguments by reference. |
| 755 | """ |
| 756 | |
| 757 | def __init__(self, decl_ty, ref_ty): |
| 758 | r""" |
| 759 | Initializes the properties decl_type and ref_type (the C type |
| 760 | names used when declaring variables and function parameters, |
| 761 | respectively), as well as the properties described in |
| 762 | the documentation for StorageType.__init__. |
| 763 | |
| 764 | EXAMPLES: |
| 765 | sage: from sage.ext.gen_interpreters import * |
| 766 | sage: ty_mpfr.class_member_declarations |
| 767 | 'cdef RealField domain\n' |
| 768 | sage: ty_mpfr.class_member_initializations |
| 769 | "self.domain = args['domain']\n" |
| 770 | sage: ty_mpfr.local_declarations |
| 771 | 'cdef RealNumber rn\n' |
| 772 | sage: ty_mpfr.decl_type |
| 773 | 'mpfr_t' |
| 774 | sage: ty_mpfr.ref_type |
| 775 | 'mpfr_ptr' |
| 776 | """ |
| 777 | StorageType.__init__(self) |
| 778 | self.decl_type = decl_ty |
| 779 | self.ref_type = ref_ty |
| 780 | |
| 781 | def c_decl_type(self): |
| 782 | r""" |
| 783 | Gives the C type for a single value of this type (as a string). |
| 784 | |
| 785 | EXAMPLES: |
| 786 | sage: from sage.ext.gen_interpreters import * |
| 787 | sage: ty_mpfr.c_decl_type() |
| 788 | 'mpfr_t' |
| 789 | """ |
| 790 | return self.decl_type |
| 791 | |
| 792 | def c_local_type(self): |
| 793 | r""" |
| 794 | Gives the C type used for a value of this type inside an |
| 795 | instruction. For assignable/cheap_copy types, this is the |
| 796 | same as c_decl_type; for auto-reference types, this is the |
| 797 | pointer type. |
| 798 | |
| 799 | EXAMPLES: |
| 800 | sage: from sage.ext.gen_interpreters import * |
| 801 | sage: ty_mpfr.c_local_type() |
| 802 | 'mpfr_ptr' |
| 803 | """ |
| 804 | return self.ref_type |
| 805 | |
| 806 | def needs_cython_init_clear(self): |
| 807 | r""" |
| 808 | Says whether values/arrays of this type need to be initialized |
| 809 | before use and cleared before the underlying memory is freed. |
| 810 | |
| 811 | All known examples of auto-reference types do need a special |
| 812 | initialization call, so this always returns True. |
| 813 | |
| 814 | EXAMPLES: |
| 815 | sage: from sage.ext.gen_interpreters import * |
| 816 | sage: ty_mpfr.needs_cython_init_clear() |
| 817 | True |
| 818 | """ |
| 819 | return True |
| 820 | |
| 821 | class StorageTypeMPFR(StorageTypeAutoReference): |
| 822 | r""" |
| 823 | StorageTypeMPFR is a subtype of StorageTypeAutoReference that deals |
| 824 | the MPFR's mpfr_t type. |
| 825 | |
| 826 | For any given program that we're interpreting, ty_mpfr can only |
| 827 | refer to a single precision. An interpreter that needs to use |
| 828 | two precisions of mpfr_t in the same program should instantiate two |
| 829 | separate instances of StorageTypeMPFR. (Interpreters that need |
| 830 | to handle arbitrarily many precisions in the same program are not |
| 831 | handled at all.) |
| 832 | """ |
| 833 | |
| 834 | def __init__(self, id=''): |
| 835 | r""" |
| 836 | Initializes the id property, as well as the properties described |
| 837 | in the documentation for StorageTypeAutoReference.__init__. |
| 838 | |
| 839 | The id property is used if you want to have an interpreter |
| 840 | that handles two instances of StorageTypeMPFR (that is, |
| 841 | handles mpfr_t variables at two different precisions |
| 842 | simultaneously). It's a string that's used to generate |
| 843 | variable names that don't conflict. (The id system has |
| 844 | never actually been used, so bugs probably remain.) |
| 845 | |
| 846 | EXAMPLES: |
| 847 | sage: from sage.ext.gen_interpreters import * |
| 848 | sage: ty_mpfr.class_member_declarations |
| 849 | 'cdef RealField domain\n' |
| 850 | sage: ty_mpfr.class_member_initializations |
| 851 | "self.domain = args['domain']\n" |
| 852 | sage: ty_mpfr.local_declarations |
| 853 | 'cdef RealNumber rn\n' |
| 854 | sage: ty_mpfr.decl_type |
| 855 | 'mpfr_t' |
| 856 | sage: ty_mpfr.ref_type |
| 857 | 'mpfr_ptr' |
| 858 | |
| 859 | TESTS: |
| 860 | sage: ty_mpfr2 = StorageTypeMPFR(id='_the_second') |
| 861 | sage: ty_mpfr2.class_member_declarations |
| 862 | 'cdef RealField domain_the_second\n' |
| 863 | sage: ty_mpfr2.class_member_initializations |
| 864 | "self.domain_the_second = args['domain_the_second']\n" |
| 865 | sage: ty_mpfr2.local_declarations |
| 866 | 'cdef RealNumber rn_the_second\n' |
| 867 | """ |
| 868 | StorageTypeAutoReference.__init__(self, 'mpfr_t', 'mpfr_ptr') |
| 869 | self.id = id |
| 870 | self.class_member_declarations = "cdef RealField domain%s\n" % self.id |
| 871 | self.class_member_initializations = \ |
| 872 | "self.domain%s = args['domain%s']\n" % (self.id, self.id) |
| 873 | self.local_declarations = "cdef RealNumber rn%s\n" % self.id |
| 874 | |
| 875 | def cython_init(self, loc): |
| 876 | r""" |
| 877 | Generates code to initialize an mpfr_t reference (a variable, an |
| 878 | array reference, etc.) |
| 879 | |
| 880 | EXAMPLES: |
| 881 | sage: from sage.ext.gen_interpreters import * |
| 882 | sage: ty_mpfr.cython_init('foo[i]') |
| 883 | u'mpfr_init2(foo[i], self.domain.prec())' |
| 884 | """ |
| 885 | return je("mpfr_init2({{ loc }}, self.domain{{ self.id }}.prec())", |
| 886 | self=self, loc=loc) |
| 887 | |
| 888 | def cython_clear(self, loc): |
| 889 | r""" |
| 890 | Generates code to clear an mpfr_t reference (a variable, an |
| 891 | array reference, etc.) |
| 892 | |
| 893 | EXAMPLES: |
| 894 | sage: from sage.ext.gen_interpreters import * |
| 895 | sage: ty_mpfr.cython_clear('foo[i]') |
| 896 | 'mpfr_clear(foo[i])' |
| 897 | """ |
| 898 | return 'mpfr_clear(%s)' % loc |
| 899 | |
| 900 | def assign_c_from_py(self, c, py): |
| 901 | r""" |
| 902 | Given a Cython variable/array reference/etc. of this storage type, |
| 903 | and a Python expression, generate code to assign to the Cython |
| 904 | variable from the Python expression. |
| 905 | |
| 906 | EXAMPLES: |
| 907 | sage: from sage.ext.gen_interpreters import * |
| 908 | sage: ty_mpfr.assign_c_from_py('foo[i]', 'bar[j]') |
| 909 | u'rn = self.domain(bar[j])\nmpfr_set(foo[i], rn.value, GMP_RNDN)' |
| 910 | """ |
| 911 | return je(""" |
| 912 | rn{{ self.id }} = self.domain({{ py }}) |
| 913 | mpfr_set({{ c }}, rn.value, GMP_RNDN)""", self=self, c=c, py=py) |
| 914 | |
| 915 | ty_mpfr = StorageTypeMPFR() |
| 916 | |
| 917 | class MemoryChunk(object): |
| 918 | r""" |
| 919 | Memory chunks control allocation, deallocation, iniialization, |
| 920 | etc. of the vectors and objects in the interpreter. Basically, |
| 921 | there is one memory chunk per argument to the C interpreter. |
| 922 | |
| 923 | There are three "generic" varieties of memory chunk: "constants", |
| 924 | "arguments", and "scratch". These are named after their most |
| 925 | common use, but they could be used for other things in some |
| 926 | interpreters. |
| 927 | |
| 928 | All three kinds of chunks are allocated in the wrapper class. |
| 929 | Constants are initialized when the wrapper is constructed; |
| 930 | arguments are initialized in the __call__ method, from the |
| 931 | caller's arguments. "scratch" chunks are not initialized at all; |
| 932 | they are used for scratch storage (often, but not necessarily, for |
| 933 | a stack) in the interpreter. |
| 934 | |
| 935 | Interpreters which need memory chunks that don't fit into these |
| 936 | categories can create new subclasses of MemoryChunk. |
| 937 | """ |
| 938 | |
| 939 | def __init__(self, name, storage_type): |
| 940 | r""" |
| 941 | Initialize an instance of MemoryChunk. |
| 942 | |
| 943 | This sets the properties "name" (the name of this memory chunk; |
| 944 | used in generated variable names, etc.) and "storage_type", |
| 945 | which is a StorageType object. |
| 946 | |
| 947 | EXAMPLES: |
| 948 | sage: from sage.ext.gen_interpreters import * |
| 949 | sage: mc = MemoryChunkArguments('args', ty_mpfr) |
| 950 | sage: mc.name |
| 951 | 'args' |
| 952 | sage: mc.storage_type is ty_mpfr |
| 953 | True |
| 954 | """ |
| 955 | self.name = name |
| 956 | self.storage_type = storage_type |
| 957 | |
| 958 | def __repr__(self): |
| 959 | r""" |
| 960 | Give a string representation of this memory chunk. |
| 961 | |
| 962 | EXAMPLES: |
| 963 | sage: from sage.ext.gen_interpreters import * |
| 964 | sage: mc = MemoryChunkArguments('args', ty_mpfr) |
| 965 | sage: mc |
| 966 | {MC:args} |
| 967 | sage: mc.__repr__() |
| 968 | '{MC:args}' |
| 969 | """ |
| 970 | return '{MC:%s}' % self.name |
| 971 | |
| 972 | def declare_class_members(self): |
| 973 | r""" |
| 974 | Returns a string giving the declarations of the class members |
| 975 | in a wrapper class for this memory chunk. |
| 976 | |
| 977 | EXAMPLES: |
| 978 | sage: from sage.ext.gen_interpreters import * |
| 979 | sage: mc = MemoryChunkArguments('args', ty_mpfr) |
| 980 | sage: mc.declare_class_members() |
| 981 | u' cdef int _n_args\n cdef mpfr_t* _args\n' |
| 982 | """ |
| 983 | return self.storage_type.declare_chunk_class_members(self.name) |
| 984 | |
| 985 | def init_class_members(self): |
| 986 | r""" |
| 987 | Returns a string to be put in the __init__ method of a wrapper |
| 988 | class using this memory chunk, to initialize the corresponding |
| 989 | class members. |
| 990 | |
| 991 | EXAMPLES: |
| 992 | sage: from sage.ext.gen_interpreters import * |
| 993 | sage: mc = MemoryChunkArguments('args', ty_mpfr) |
| 994 | sage: print mc.init_class_members() |
| 995 | count = args['args'] |
| 996 | self._n_args = count |
| 997 | self._args = <mpfr_t*>sage_malloc(sizeof(mpfr_t) * count) |
| 998 | if self._args == NULL: raise MemoryError |
| 999 | for i in range(count): |
| 1000 | mpfr_init2(self._args[i], self.domain.prec()) |
| 1001 | <BLANKLINE> |
| 1002 | """ |
| 1003 | return "" |
| 1004 | |
| 1005 | def dealloc_class_members(self): |
| 1006 | r""" |
| 1007 | Returns a string to be put in the __dealloc__ method of a wrapper |
| 1008 | class using this memory chunk, to deallocate the corresponding |
| 1009 | class members. |
| 1010 | |
| 1011 | EXAMPLES: |
| 1012 | sage: from sage.ext.gen_interpreters import * |
| 1013 | sage: mc = MemoryChunkArguments('args', ty_mpfr) |
| 1014 | sage: print mc.dealloc_class_members() |
| 1015 | if self._args: |
| 1016 | for i in range(self._n_args): |
| 1017 | mpfr_clear(self._args[i]) |
| 1018 | sage_free(self._args) |
| 1019 | <BLANKLINE> |
| 1020 | """ |
| 1021 | return "" |
| 1022 | |
| 1023 | def declare_parameter(self): |
| 1024 | r""" |
| 1025 | Returns the string to use to declare the interpreter parameter |
| 1026 | corresponding to this memory chunk. |
| 1027 | |
| 1028 | EXAMPLES: |
| 1029 | sage: from sage.ext.gen_interpreters import * |
| 1030 | sage: mc = MemoryChunkArguments('args', ty_mpfr) |
| 1031 | sage: mc.declare_parameter() |
| 1032 | 'mpfr_t* args' |
| 1033 | """ |
| 1034 | return '%s %s' % (self.storage_type.c_ptr_type(), self.name) |
| 1035 | |
| 1036 | def declare_call_locals(self): |
| 1037 | r""" |
| 1038 | Returns a string to put in the __call__ method of a wrapper |
| 1039 | class using this memory chunk, to allocate local variables. |
| 1040 | |
| 1041 | EXAMPLES: |
| 1042 | sage: from sage.ext.gen_interpreters import * |
| 1043 | sage: mc = MemoryChunkRRRetval('retval', ty_mpfr) |
| 1044 | sage: mc.declare_call_locals() |
| 1045 | u' cdef RealNumber retval = (self.domain)()\n' |
| 1046 | """ |
| 1047 | return "" |
| 1048 | |
| 1049 | def pass_argument(self): |
| 1050 | r""" |
| 1051 | Returns the string to pass the argument corresponding to this |
| 1052 | memory chunk to the interpreter. |
| 1053 | |
| 1054 | EXAMPLES: |
| 1055 | sage: from sage.ext.gen_interpreters import * |
| 1056 | sage: mc = MemoryChunkConstants('constants', ty_mpfr) |
| 1057 | sage: mc.pass_argument() |
| 1058 | 'self._constants' |
| 1059 | """ |
| 1060 | raise NotImplementedError |
| 1061 | |
| 1062 | def needs_cleanup_on_error(self): |
| 1063 | r""" |
| 1064 | In an interpreter that can terminate prematurely (due to an |
| 1065 | exception from calling Python code, or divide by zero, or |
| 1066 | whatever) it will just return at the end of the current instruction, |
| 1067 | skipping the rest of the program. Thus, it may still have |
| 1068 | values pushed on the stack, etc. |
| 1069 | |
| 1070 | This method returns True if this memory chunk is modified by the |
| 1071 | interpreter and needs some sort of cleanup when an error happens. |
| 1072 | |
| 1073 | EXAMPLES: |
| 1074 | sage: from sage.ext.gen_interpreters import * |
| 1075 | sage: mc = MemoryChunkConstants('constants', ty_mpfr) |
| 1076 | sage: mc.needs_cleanup_on_error() |
| 1077 | False |
| 1078 | """ |
| 1079 | return False |
| 1080 | |
| 1081 | def is_stack(self): |
| 1082 | r""" |
| 1083 | Says whether this memory chunk is a stack. This affects code |
| 1084 | generation for instructions using this memory chunk. |
| 1085 | |
| 1086 | It would be nicer to make this object-oriented somehow, so |
| 1087 | that the code generator called MemoryChunk methods instead of |
| 1088 | using |
| 1089 | if ch.is_stack(): |
| 1090 | ... hardcoded stack code |
| 1091 | else: |
| 1092 | ... hardcoded non-stack code |
| 1093 | but that hasn't been done yet. |
| 1094 | |
| 1095 | EXAMPLES: |
| 1096 | sage: from sage.ext.gen_interpreters import * |
| 1097 | sage: mc = MemoryChunkScratch('scratch', ty_mpfr) |
| 1098 | sage: mc.is_stack() |
| 1099 | False |
| 1100 | sage: mc = MemoryChunkScratch('stack', ty_mpfr, is_stack=True) |
| 1101 | sage: mc.is_stack() |
| 1102 | True |
| 1103 | """ |
| 1104 | return False |
| 1105 | |
| 1106 | def is_python_refcounted_stack(self): |
| 1107 | r""" |
| 1108 | Says whether this memory chunk refers to a stack where the entries |
| 1109 | need to be INCREF/DECREF'ed. |
| 1110 | |
| 1111 | It would be nice to make this object-oriented, so that the |
| 1112 | code generator called MemoryChunk methods to do the potential |
| 1113 | INCREF/DECREF and didn't have to explicitly test |
| 1114 | is_python_refcounted_stack. |
| 1115 | |
| 1116 | EXAMPLES: |
| 1117 | sage: from sage.ext.gen_interpreters import * |
| 1118 | sage: mc = MemoryChunkScratch('args', ty_python) |
| 1119 | sage: mc.is_python_refcounted_stack() |
| 1120 | False |
| 1121 | sage: mc = MemoryChunkScratch('args', ty_python, is_stack=True) |
| 1122 | sage: mc.is_python_refcounted_stack() |
| 1123 | True |
| 1124 | sage: mc = MemoryChunkScratch('args', ty_mpfr, is_stack=True) |
| 1125 | sage: mc.is_python_refcounted_stack() |
| 1126 | False |
| 1127 | """ |
| 1128 | return self.is_stack() and self.storage_type.python_refcounted() |
| 1129 | |
| 1130 | class MemoryChunkLonglivedArray(MemoryChunk): |
| 1131 | r""" |
| 1132 | MemoryChunkLonglivedArray is a subtype of MemoryChunk that deals |
| 1133 | with memory chunks that are both 1) allocated as class members (rather |
| 1134 | than being allocated in __call__) and 2) are arrays. |
| 1135 | """ |
| 1136 | |
| 1137 | def init_class_members(self): |
| 1138 | r""" |
| 1139 | Returns a string to be put in the __init__ method of a wrapper |
| 1140 | class using this memory chunk, to initialize the corresponding |
| 1141 | class members. |
| 1142 | |
| 1143 | EXAMPLES: |
| 1144 | sage: from sage.ext.gen_interpreters import * |
| 1145 | sage: mc = MemoryChunkArguments('args', ty_double) |
| 1146 | sage: print mc.init_class_members() |
| 1147 | count = args['args'] |
| 1148 | self._n_args = count |
| 1149 | self._args = <double*>sage_malloc(sizeof(double) * count) |
| 1150 | if self._args == NULL: raise MemoryError |
| 1151 | <BLANKLINE> |
| 1152 | """ |
| 1153 | return je(""" |
| 1154 | count = args['{{ self.name }}'] |
| 1155 | {% print self.storage_type.alloc_chunk_data(self.name, 'count') %} |
| 1156 | """, self=self) |
| 1157 | |
| 1158 | def dealloc_class_members(self): |
| 1159 | r""" |
| 1160 | Returns a string to be put in the __dealloc__ method of a wrapper |
| 1161 | class using this memory chunk, to deallocate the corresponding |
| 1162 | class members. |
| 1163 | |
| 1164 | EXAMPLES: |
| 1165 | sage: from sage.ext.gen_interpreters import * |
| 1166 | sage: mc = MemoryChunkArguments('args', ty_mpfr) |
| 1167 | sage: print mc.dealloc_class_members() |
| 1168 | if self._args: |
| 1169 | for i in range(self._n_args): |
| 1170 | mpfr_clear(self._args[i]) |
| 1171 | sage_free(self._args) |
| 1172 | <BLANKLINE> |
| 1173 | """ |
| 1174 | return self.storage_type.dealloc_chunk_data(self.name) |
| 1175 | |
| 1176 | def pass_argument(self): |
| 1177 | r""" |
| 1178 | Returns the string to pass the argument corresponding to this |
| 1179 | memory chunk to the interpreter. |
| 1180 | |
| 1181 | EXAMPLES: |
| 1182 | sage: from sage.ext.gen_interpreters import * |
| 1183 | sage: mc = MemoryChunkConstants('constants', ty_mpfr) |
| 1184 | sage: mc.pass_argument() |
| 1185 | 'self._constants' |
| 1186 | """ |
| 1187 | return 'self._%s' % self.name |
| 1188 | |
| 1189 | class MemoryChunkConstants(MemoryChunkLonglivedArray): |
| 1190 | r""" |
| 1191 | MemoryChunkConstants is a subtype of MemoryChunkLonglivedArray. |
| 1192 | |
| 1193 | MemoryChunkConstants chunks have their contents set in the |
| 1194 | wrapper's __init__ method (and not changed afterward). |
| 1195 | """ |
| 1196 | |
| 1197 | def init_class_members(self): |
| 1198 | r""" |
| 1199 | Returns a string to be put in the __init__ method of a wrapper |
| 1200 | class using this memory chunk, to initialize the corresponding |
| 1201 | class members. |
| 1202 | |
| 1203 | EXAMPLES: |
| 1204 | sage: from sage.ext.gen_interpreters import * |
| 1205 | sage: mc = MemoryChunkConstants('constants', ty_mpfr) |
| 1206 | sage: print mc.init_class_members() |
| 1207 | val = args['constants'] |
| 1208 | self._n_constants = len(val) |
| 1209 | self._constants = <mpfr_t*>sage_malloc(sizeof(mpfr_t) * len(val)) |
| 1210 | if self._constants == NULL: raise MemoryError |
| 1211 | for i in range(len(val)): |
| 1212 | mpfr_init2(self._constants[i], self.domain.prec()) |
| 1213 | for i in range(len(val)): |
| 1214 | rn = self.domain(val[i]) |
| 1215 | mpfr_set(self._constants[i], rn.value, GMP_RNDN) |
| 1216 | <BLANKLINE> |
| 1217 | """ |
| 1218 | return je(""" |
| 1219 | val = args['{{ self.name }}'] |
| 1220 | {% print self.storage_type.alloc_chunk_data(self.name, 'len(val)') %} |
| 1221 | for i in range(len(val)): |
| 1222 | {{ self.storage_type.assign_c_from_py('self._%s[i]' % self.name, 'val[i]') | i(12) }} |
| 1223 | """, self=self) |
| 1224 | |
| 1225 | class MemoryChunkArguments(MemoryChunkLonglivedArray): |
| 1226 | r""" |
| 1227 | MemoryChunkArguments is a subtype of MemoryChunkLonglivedArray, |
| 1228 | for dealing with arguments to the wrapper's __call__ method. |
| 1229 | |
| 1230 | Currently the __call__ method is declared to take a varargs |
| 1231 | *args argument tuple. We assume that the MemoryChunk named 'args' |
| 1232 | will deal with that tuple. |
| 1233 | """ |
| 1234 | |
| 1235 | def setup_args(self): |
| 1236 | r""" |
| 1237 | Handle the arguments of __call__ -- copy them into a pre-allocated |
| 1238 | array, ready to pass to the interpreter. |
| 1239 | |
| 1240 | EXAMPLES: |
| 1241 | sage: from sage.ext.gen_interpreters import * |
| 1242 | sage: mc = MemoryChunkArguments('args', ty_mpfr) |
| 1243 | sage: print mc.setup_args() |
| 1244 | cdef mpfr_t* c_args = self._args |
| 1245 | cdef int i |
| 1246 | for i from 0 <= i < len(args): |
| 1247 | rn = self.domain(args[i]) |
| 1248 | mpfr_set(self._args[i], rn.value, GMP_RNDN) |
| 1249 | <BLANKLINE> |
| 1250 | """ |
| 1251 | return je(""" |
| 1252 | cdef {{ self.storage_type.c_ptr_type() }} c_args = self._args |
| 1253 | cdef int i |
| 1254 | for i from 0 <= i < len(args): |
| 1255 | {{ self.storage_type.assign_c_from_py('self._args[i]', 'args[i]') | i(4) }} |
| 1256 | """, self=self) |
| 1257 | |
| 1258 | def pass_argument(self): |
| 1259 | r""" |
| 1260 | Returns the string to pass the argument corresponding to this |
| 1261 | memory chunk to the interpreter. |
| 1262 | |
| 1263 | EXAMPLES: |
| 1264 | sage: from sage.ext.gen_interpreters import * |
| 1265 | sage: mc = MemoryChunkArguments('args', ty_mpfr) |
| 1266 | sage: mc.pass_argument() |
| 1267 | 'c_args' |
| 1268 | """ |
| 1269 | return 'c_args' |
| 1270 | |
| 1271 | class MemoryChunkScratch(MemoryChunkLonglivedArray): |
| 1272 | r""" |
| 1273 | MemoryChunkScratch is a subtype of MemoryChunkLonglivedArray |
| 1274 | for dealing with memory chunks that are allocated in the wrapper, |
| 1275 | but only used in the interpreter -- stacks, scratch registers, etc. |
| 1276 | |
| 1277 | (Currently these are only used as stacks.) |
| 1278 | """ |
| 1279 | |
| 1280 | def __init__(self, name, storage_type, is_stack=False): |
| 1281 | r""" |
| 1282 | Initialize an instance of MemoryChunkScratch. |
| 1283 | |
| 1284 | Initializes the _is_stack property, as well as |
| 1285 | the properties described in the documentation for |
| 1286 | MemoryChunk.__init__. |
| 1287 | |
| 1288 | EXAMPLES: |
| 1289 | sage: from sage.ext.gen_interpreters import * |
| 1290 | sage: mc = MemoryChunkScratch('stack', ty_double, is_stack=True) |
| 1291 | sage: mc.name |
| 1292 | 'stack' |
| 1293 | sage: mc.storage_type is ty_double |
| 1294 | True |
| 1295 | sage: mc._is_stack |
| 1296 | True |
| 1297 | """ |
| 1298 | MemoryChunkLonglivedArray.__init__(self, name, storage_type) |
| 1299 | self._is_stack = is_stack |
| 1300 | |
| 1301 | def is_stack(self): |
| 1302 | r""" |
| 1303 | Says whether this memory chunk is a stack. This affects code |
| 1304 | generation for instructions using this memory chunk. |
| 1305 | |
| 1306 | EXAMPLES: |
| 1307 | sage: from sage.ext.gen_interpreters import * |
| 1308 | sage: mc = MemoryChunkScratch('stack', ty_mpfr, is_stack=True) |
| 1309 | sage: mc.is_stack() |
| 1310 | True |
| 1311 | """ |
| 1312 | return self._is_stack |
| 1313 | |
| 1314 | def needs_cleanup_on_error(self): |
| 1315 | r""" |
| 1316 | In an interpreter that can terminate prematurely (due to an |
| 1317 | exception from calling Python code, or divide by zero, or |
| 1318 | whatever) it will just return at the end of the current instruction, |
| 1319 | skipping the rest of the program. Thus, it may still have |
| 1320 | values pushed on the stack, etc. |
| 1321 | |
| 1322 | This method returns True if this memory chunk is modified by the |
| 1323 | interpreter and needs some sort of cleanup when an error happens. |
| 1324 | |
| 1325 | EXAMPLES: |
| 1326 | sage: from sage.ext.gen_interpreters import * |
| 1327 | sage: mc = MemoryChunkScratch('registers', ty_python) |
| 1328 | sage: mc.needs_cleanup_on_error() |
| 1329 | True |
| 1330 | """ |
| 1331 | return self.storage_type.python_refcounted() |
| 1332 | |
| 1333 | def handle_cleanup(self): |
| 1334 | r""" |
| 1335 | Handle the cleanup if the interpreter exits with an error. |
| 1336 | |
| 1337 | For scratch/stack chunks that hold Python-refcounted values, |
| 1338 | we assume that they are filled with NULL on every entry to the |
| 1339 | interpreter. If the interpreter exited with an error, it may |
| 1340 | have left values in the chunk, so we need to go through |
| 1341 | the chunk and Py_CLEAR it. |
| 1342 | |
| 1343 | EXAMPLES: |
| 1344 | sage: from sage.ext.gen_interpreters import * |
| 1345 | sage: mc = MemoryChunkScratch('registers', ty_python) |
| 1346 | sage: print mc.handle_cleanup() |
| 1347 | for i in range(self._n_registers): |
| 1348 | Py_CLEAR(self._registers[i]) |
| 1349 | <BLANKLINE> """ |
| 1350 | # XXX This is a lot slower than it needs to be, because |
| 1351 | # we don't have a "cdef int i" in scope here. |
| 1352 | return je(""" |
| 1353 | for i in range(self._n_{{ self.name }}): |
| 1354 | Py_CLEAR(self._{{ self.name }}[i]) |
| 1355 | """, self=self) |
| 1356 | |
| 1357 | class MemoryChunkRRRetval(MemoryChunk): |
| 1358 | r""" |
| 1359 | A special-purpose memory chunk, for dealing with the return value |
| 1360 | of the RR-based interpreter. |
| 1361 | """ |
| 1362 | |
| 1363 | def declare_class_members(self): |
| 1364 | r""" |
| 1365 | Returns a string giving the declarations of the class members |
| 1366 | in a wrapper class for this memory chunk. |
| 1367 | |
| 1368 | EXAMPLES: |
| 1369 | sage: from sage.ext.gen_interpreters import * |
| 1370 | sage: mc = MemoryChunkRRRetval('retval', ty_mpfr) |
| 1371 | sage: mc.declare_class_members() |
| 1372 | '' |
| 1373 | """ |
| 1374 | return "" |
| 1375 | |
| 1376 | def declare_call_locals(self): |
| 1377 | r""" |
| 1378 | Returns a string to put in the __call__ method of a wrapper |
| 1379 | class using this memory chunk, to allocate local variables. |
| 1380 | |
| 1381 | EXAMPLES: |
| 1382 | sage: from sage.ext.gen_interpreters import * |
| 1383 | sage: mc = MemoryChunkRRRetval('retval', ty_mpfr) |
| 1384 | sage: mc.declare_call_locals() |
| 1385 | u' cdef RealNumber retval = (self.domain)()\n' |
| 1386 | """ |
| 1387 | return je(""" |
| 1388 | cdef RealNumber {{ self.name }} = (self.domain)() |
| 1389 | """, self=self) |
| 1390 | |
| 1391 | def pass_argument(self): |
| 1392 | r""" |
| 1393 | Returns the string to pass the argument corresponding to this |
| 1394 | memory chunk to the interpreter. |
| 1395 | |
| 1396 | EXAMPLES: |
| 1397 | sage: from sage.ext.gen_interpreters import * |
| 1398 | sage: mc = MemoryChunkRRRetval('retval', ty_mpfr) |
| 1399 | sage: mc.pass_argument() |
| 1400 | u'&retval.value' |
| 1401 | """ |
| 1402 | return je("""&{{ self.name }}.value""", self=self) |
| 1403 | |
| 1404 | class MemoryChunkPythonArguments(MemoryChunk): |
| 1405 | r""" |
| 1406 | A special-purpose memory chunk, for the generic Python-object based |
| 1407 | interpreter. Rather than copy the arguments into an array allocated |
| 1408 | in the wrapper, we use the PyTupleObject internals and pass the array |
| 1409 | that's inside the argument tuple. |
| 1410 | """ |
| 1411 | |
| 1412 | def declare_class_members(self): |
| 1413 | r""" |
| 1414 | Returns a string giving the declarations of the class members |
| 1415 | in a wrapper class for this memory chunk. |
| 1416 | |
| 1417 | EXAMPLES: |
| 1418 | sage: from sage.ext.gen_interpreters import * |
| 1419 | sage: mc = MemoryChunkPythonArguments('args', ty_python) |
| 1420 | """ |
| 1421 | return " cdef int _n_%s\n" % self.name |
| 1422 | |
| 1423 | def init_class_members(self): |
| 1424 | r""" |
| 1425 | Returns a string to be put in the __init__ method of a wrapper |
| 1426 | class using this memory chunk, to initialize the corresponding |
| 1427 | class members. |
| 1428 | |
| 1429 | EXAMPLES: |
| 1430 | sage: from sage.ext.gen_interpreters import * |
| 1431 | sage: mc = MemoryChunkPythonArguments('args', ty_python) |
| 1432 | sage: mc.init_class_members() |
| 1433 | u" count = args['args']\n self._n_args = count\n" |
| 1434 | """ |
| 1435 | return je(""" |
| 1436 | count = args['{{ self.name }}'] |
| 1437 | self._n_args = count |
| 1438 | """, self=self) |
| 1439 | |
| 1440 | def setup_args(self): |
| 1441 | r""" |
| 1442 | Handle the arguments of __call__. Nothing to do. |
| 1443 | |
| 1444 | EXAMPLES: |
| 1445 | sage: from sage.ext.gen_interpreters import * |
| 1446 | sage: mc = MemoryChunkPythonArguments('args', ty_python) |
| 1447 | sage: mc.setup_args() |
| 1448 | '' |
| 1449 | """ |
| 1450 | return '' |
| 1451 | |
| 1452 | def pass_argument(self): |
| 1453 | r""" |
| 1454 | Pass the innards of the argument tuple to the interpreter. |
| 1455 | |
| 1456 | EXAMPLES: |
| 1457 | sage: from sage.ext.gen_interpreters import * |
| 1458 | sage: mc = MemoryChunkPythonArguments('args', ty_python) |
| 1459 | sage: mc.pass_argument() |
| 1460 | '(<PyTupleObject*>args).ob_item' |
| 1461 | """ |
| 1462 | return "(<PyTupleObject*>args).ob_item" |
| 1463 | |
| 1464 | class MemoryChunkElementArguments(MemoryChunkPythonArguments): |
| 1465 | r""" |
| 1466 | A special-purpose memory chunk, for the Python-object based |
| 1467 | interpreters that want to process (and perhaps modify) the data. |
| 1468 | |
| 1469 | We allocate a new list (via the map function) on every call to |
| 1470 | hold the modified arguments. That's not strictly necessary -- |
| 1471 | we could pre-allocate a list and map into it -- but this lets us |
| 1472 | use simpler code for a very-likely-negligible efficiency cost. |
| 1473 | (The Element interpreter is going to allocate lots of objects |
| 1474 | as it runs, anyway.) |
| 1475 | """ |
| 1476 | |
| 1477 | def setup_args(self): |
| 1478 | r""" |
| 1479 | Handle the arguments of __call__. Note: This hardcodes |
| 1480 | "self._domain". |
| 1481 | |
| 1482 | EXAMPLES: |
| 1483 | sage: from sage.ext.gen_interpreters import * |
| 1484 | sage: mc = MemoryChunkElementArguments('args', ty_python) |
| 1485 | sage: mc.setup_args() |
| 1486 | 'mapped_args = map(self._domain, args)\n' |
| 1487 | """ |
| 1488 | return "mapped_args = map(self._domain, args)\n" |
| 1489 | |
| 1490 | def pass_argument(self): |
| 1491 | r""" |
| 1492 | Pass the innards of the argument tuple to the interpreter. |
| 1493 | |
| 1494 | EXAMPLES: |
| 1495 | sage: from sage.ext.gen_interpreters import * |
| 1496 | sage: mc = MemoryChunkElementArguments('args', ty_python) |
| 1497 | sage: mc.pass_argument() |
| 1498 | '(<PyListObject*>mapped_args).ob_item' |
| 1499 | """ |
| 1500 | return "(<PyListObject*>mapped_args).ob_item" |
| 1501 | |
| 1502 | class MemoryChunkPyConstant(MemoryChunk): |
| 1503 | r""" |
| 1504 | A special-purpose memory chunk, for holding a single Python constant |
| 1505 | and passing it to the interpreter as a PyObject*. |
| 1506 | """ |
| 1507 | |
| 1508 | def __init__(self, name): |
| 1509 | r""" |
| 1510 | Initialize an instance of MemoryChunkPyConstant. |
| 1511 | |
| 1512 | Always uses the type ty_python. |
| 1513 | |
| 1514 | EXAMPLES: |
| 1515 | sage: from sage.ext.gen_interpreters import * |
| 1516 | sage: mc = MemoryChunkPyConstant('domain') |
| 1517 | sage: mc.name |
| 1518 | 'domain' |
| 1519 | sage: mc.storage_type is ty_python |
| 1520 | True |
| 1521 | """ |
| 1522 | MemoryChunk.__init__(self, name, ty_python) |
| 1523 | |
| 1524 | def declare_class_members(self): |
| 1525 | r""" |
| 1526 | Returns a string giving the declarations of the class members |
| 1527 | in a wrapper class for this memory chunk. |
| 1528 | |
| 1529 | EXAMPLES: |
| 1530 | sage: from sage.ext.gen_interpreters import * |
| 1531 | sage: mc = MemoryChunkPyConstant('domain') |
| 1532 | sage: mc.declare_class_members() |
| 1533 | u' cdef object _domain\n' |
| 1534 | """ |
| 1535 | return je(""" |
| 1536 | cdef object _{{ self.name }} |
| 1537 | """, self=self) |
| 1538 | |
| 1539 | def init_class_members(self): |
| 1540 | r""" |
| 1541 | Returns a string to be put in the __init__ method of a wrapper |
| 1542 | class using this memory chunk, to initialize the corresponding |
| 1543 | class members. |
| 1544 | |
| 1545 | EXAMPLES: |
| 1546 | sage: from sage.ext.gen_interpreters import * |
| 1547 | sage: mc = MemoryChunkPyConstant('domain') |
| 1548 | sage: mc.init_class_members() |
| 1549 | u" self._domain = args['domain']\n" |
| 1550 | """ |
| 1551 | return je(""" |
| 1552 | self._{{ self.name }} = args['{{ self.name }}'] |
| 1553 | """, self=self) |
| 1554 | |
| 1555 | def declare_parameter(self): |
| 1556 | r""" |
| 1557 | Returns the string to use to declare the interpreter parameter |
| 1558 | corresponding to this memory chunk. |
| 1559 | |
| 1560 | EXAMPLES: |
| 1561 | sage: from sage.ext.gen_interpreters import * |
| 1562 | sage: mc = MemoryChunkPyConstant('domain') |
| 1563 | sage: mc.declare_parameter() |
| 1564 | 'PyObject* domain' |
| 1565 | """ |
| 1566 | return 'PyObject* %s' % self.name |
| 1567 | |
| 1568 | def pass_argument(self): |
| 1569 | r""" |
| 1570 | Returns the string to pass the argument corresponding to this |
| 1571 | memory chunk to the interpreter. |
| 1572 | |
| 1573 | EXAMPLES: |
| 1574 | sage: from sage.ext.gen_interpreters import * |
| 1575 | sage: mc = MemoryChunkPyConstant('domain') |
| 1576 | sage: mc.pass_argument() |
| 1577 | '<PyObject*>self._domain' |
| 1578 | """ |
| 1579 | return '<PyObject*>self._%s' % self.name |
| 1580 | |
| 1581 | def params_gen(**chunks): |
| 1582 | r""" |
| 1583 | Instructions have a parameter specification that says where they get |
| 1584 | their inputs and where their outputs go. Each parameter has |
| 1585 | the same form: it is a triple (chunk, addr, len). The chunk says |
| 1586 | where the parameter is read from/written to. The addr says which |
| 1587 | value in the chunk is used. If the chunk is a stack chunk, then |
| 1588 | addr must be null; the value will be read from/written to the top |
| 1589 | of the stack. Otherwise, addr must be an integer, or another chunk; |
| 1590 | if addr is another chunk, then the next value is read from that chunk |
| 1591 | to be the address. |
| 1592 | |
| 1593 | The len says how many values to read/write. It can be either None |
| 1594 | (meaning to read/write only a single value), an integer, or |
| 1595 | another chunk; if it is a chunk, then the next value is read from that |
| 1596 | chunk to be the len. Note that specifying len changes the types |
| 1597 | given to the instruction, so len==None is different than len==1 even |
| 1598 | though both mean to use a single value. |
| 1599 | |
| 1600 | These parameter specifications are cumbersome to write by hand, so |
| 1601 | there's also a simple string format for them. This (curried) |
| 1602 | function parses the simple string format and produces parameter |
| 1603 | specifications. The params_gen function takes keyword arguments |
| 1604 | mapping single-character names to memory chunks. The string format |
| 1605 | uses these names. The params_gen function returns another function, |
| 1606 | that takes two strings and returns a pair of lists of parameter |
| 1607 | specifications. |
| 1608 | |
| 1609 | Each string is the concatenation of arbitrarily many specifications. |
| 1610 | Each specification consists of an address and a length. The |
| 1611 | address is either a single character naming a stack chunk, |
| 1612 | or a string of the form 'A[B]' where A names a non-stack chunk |
| 1613 | and B names the code chunk. The length is either empty, or '@n' |
| 1614 | for a number n (meaning to use that many arguments), or '@C', where |
| 1615 | C is the code chunk. |
| 1616 | |
| 1617 | EXAMPLES: |
| 1618 | sage: from sage.ext.gen_interpreters import * |
| 1619 | sage: mc_stack = MemoryChunkScratch('stack', ty_double, is_stack=True) |
| 1620 | sage: mc_args = MemoryChunkArguments('args', ty_double) |
| 1621 | sage: mc_code = MemoryChunkConstants('code', ty_int) |
| 1622 | |
| 1623 | sage: pg = params_gen(D=mc_code, A=mc_args, S=mc_stack) |
| 1624 | sage: pg('S', '') |
| 1625 | ([({MC:stack}, None, None)], []) |
| 1626 | sage: pg('A[D]', '') |
| 1627 | ([({MC:args}, {MC:code}, None)], []) |
| 1628 | sage: pg('S@5', '') |
| 1629 | ([({MC:stack}, None, 5)], []) |
| 1630 | sage: pg('S@D', '') |
| 1631 | ([({MC:stack}, None, {MC:code})], []) |
| 1632 | sage: pg('A[D]@D', '') |
| 1633 | ([({MC:args}, {MC:code}, {MC:code})], []) |
| 1634 | sage: pg('SSS@D', 'A[D]S@D') |
| 1635 | ([({MC:stack}, None, None), ({MC:stack}, None, None), ({MC:stack}, None, {MC:code})], [({MC:args}, {MC:code}, None), ({MC:stack}, None, {MC:code})]) |
| 1636 | """ |
| 1637 | |
| 1638 | def make_params(s): |
| 1639 | p = [] |
| 1640 | s = s.strip() |
| 1641 | while s: |
| 1642 | chunk_code = s[0] |
| 1643 | s = s[1:] |
| 1644 | chunk = chunks[chunk_code] |
| 1645 | addr = None |
| 1646 | ch_len = None |
| 1647 | if chunk.is_stack(): |
| 1648 | pass |
| 1649 | else: |
| 1650 | m = re.match(r'\[(?:([0-9]+)|([a-zA-Z]))\]', s) |
| 1651 | if m.group(1): |
| 1652 | addr = int(m.group(1)) |
| 1653 | else: |
| 1654 | ch = chunks[m.group(2)] |
| 1655 | assert ch.storage_type is ty_int |
| 1656 | addr = ch |
| 1657 | s = s[m.end():].strip() |
| 1658 | if len(s) and s[0] == '@': |
| 1659 | m = re.match(r'@(?:([0-9]+)|([a-zA-Z]))', s) |
| 1660 | if m.group(1): |
| 1661 | ch_len = int(m.group(1)) |
| 1662 | else: |
| 1663 | ch = chunks[m.group(2)] |
| 1664 | assert ch.storage_type is ty_int |
| 1665 | ch_len = ch |
| 1666 | s = s[m.end():].strip() |
| 1667 | p.append((chunk, addr, ch_len)) |
| 1668 | return p |
| 1669 | |
| 1670 | def params(s_ins, s_outs): |
| 1671 | ins = make_params(s_ins) |
| 1672 | outs = make_params(s_outs) |
| 1673 | return (ins, outs) |
| 1674 | |
| 1675 | return params |
| 1676 | |
| 1677 | def string_of_addr(a): |
| 1678 | r""" |
| 1679 | An address or a length from a parameter specification may be |
| 1680 | either None, an integer, or a MemoryChunk. If the address or |
| 1681 | length is an integer or a MemoryChunk, this function will convert |
| 1682 | it to a string giving an expression that will evaluate to the correct |
| 1683 | address or length. (See the docstring for params_gen for more |
| 1684 | information on parameter specifications.) |
| 1685 | |
| 1686 | EXAMPLES: |
| 1687 | sage: from sage.ext.gen_interpreters import * |
| 1688 | sage: mc_code = MemoryChunkConstants('code', ty_int) |
| 1689 | sage: string_of_addr(mc_code) |
| 1690 | '*code++' |
| 1691 | sage: string_of_addr(42r) |
| 1692 | '42' |
| 1693 | """ |
| 1694 | if isinstance(a, (int, long)): |
| 1695 | return str(a) |
| 1696 | assert(isinstance(a, MemoryChunk)) |
| 1697 | return '*%s++' % a.name |
| 1698 | |
| 1699 | class InstrSpec(object): |
| 1700 | r""" |
| 1701 | Each instruction in an interpreter is represented as an InstrSpec. |
| 1702 | This contains all the information that we need to generate code |
| 1703 | to interpret the instruction; it also is used to build the tables |
| 1704 | that fast_callable uses, so this is the nexus point between |
| 1705 | users of the interpreter (possibly pure Python) and the |
| 1706 | generated C interpreter. |
| 1707 | |
| 1708 | The underlying instructions are matched to the caller by name. |
| 1709 | For instance, fast_callable assumes that if the interpreter has an |
| 1710 | instruction named 'cos', then it will take a single argument, |
| 1711 | return a single result, and implement the cos() function. |
| 1712 | |
| 1713 | The print representation of an instruction (which will probably |
| 1714 | only be used when doctesting this file) consists of the name, |
| 1715 | a simplified stack effect, and the code (truncated if it's long). |
| 1716 | The stack effect has two parts, the input and the output, separated |
| 1717 | by '->'; the input shows what will be popped from the stack, |
| 1718 | the output what will be placed on the stack. Each consists of |
| 1719 | a sequence of 'S' and '*' characters, where 'S' refers to a single |
| 1720 | argument and '*' refers to a variable number of arguments. |
| 1721 | |
| 1722 | The code for an instruction is a small snippet of C code. It has |
| 1723 | available variables 'i0', 'i1', ..., 'o0', 'o1', ...; one variable |
| 1724 | for each input and output; its job is to assign values to the output |
| 1725 | variables, based on the values of the input variables. |
| 1726 | |
| 1727 | Normally, in an interpreter that uses doubles, each of the input |
| 1728 | and output variables will be a double. If i0 actually represents |
| 1729 | a variable number of arguments, then it will be a pointer to |
| 1730 | double instead, and there will be another variable n_i0 giving |
| 1731 | the actual number of arguments. |
| 1732 | |
| 1733 | When instructions refer to auto-reference types, they actually |
| 1734 | get a pointer to the data in its original location; it is |
| 1735 | not copied into a local variable. Mostly, this makes no difference, |
| 1736 | but there is one potential problem to be aware of. It is possible |
| 1737 | for an output variable to point to the same object as an input |
| 1738 | variable; in fact, this usually will happen when you're working |
| 1739 | with the stack. If the instruction maps to a single function call, |
| 1740 | then this is fine; the standard auto-reference implementations |
| 1741 | (GMP, MPFR, etc.) are careful to allow having the input and output |
| 1742 | be the same. But if the instruction maps to multiple function |
| 1743 | calls, you may need to use a temporary variable. |
| 1744 | |
| 1745 | Here's an example of this issue. Suppose you want to make an |
| 1746 | instruction that does ``out = a+b*c``. You write code like this: |
| 1747 | out = b*c |
| 1748 | out = a+out |
| 1749 | But out will actually share the same storage as a; so the first line |
| 1750 | modifies a, and you actually end up computing 2*(b+c). The fix |
| 1751 | is to only write to the output once, at the very end of your |
| 1752 | instruction. |
| 1753 | |
| 1754 | Instructions are also allowed to access memory chunks (other than |
| 1755 | the stack and code) directly. They are available as C variables |
| 1756 | with the same name as the chunk. This is useful if some type of |
| 1757 | memory chunk doesn't fit well with the params_gen interface. |
| 1758 | |
| 1759 | There are additional reference-counting rules that must be |
| 1760 | followed if your interpreter operates on Python objects; these |
| 1761 | rules are described in the docstring of the PythonInterpreter |
| 1762 | class. |
| 1763 | |
| 1764 | EXAMPLES: |
| 1765 | sage: from sage.ext.gen_interpreters import * |
| 1766 | sage: pg = RDFInterpreter().pg |
| 1767 | sage: InstrSpec('add', pg('SS','S'), code='o0 = i0+i1;') |
| 1768 | add: SS->S = 'o0 = i0+i1;' |
| 1769 | """ |
| 1770 | |
| 1771 | def __init__(self, name, io, code=None, uses_error_handler=False, handles_own_decref=False): |
| 1772 | r""" |
| 1773 | Initialize an InstrSpec. |
| 1774 | |
| 1775 | INPUTS: |
| 1776 | name -- the name of the instruction |
| 1777 | io -- a pair of lists of parameter specifications for I/O of the |
| 1778 | instruction |
| 1779 | code -- a string containing a snippet of C code to read |
| 1780 | from the input variables and write to the output variables |
| 1781 | uses_error_handler -- True if the instruction calls Python |
| 1782 | and jumps to error: on a Python error |
| 1783 | handles_own_decref -- True if the instruction handles Python |
| 1784 | objects and includes its own |
| 1785 | reference-counting |
| 1786 | |
| 1787 | EXAMPLES: |
| 1788 | sage: from sage.ext.gen_interpreters import * |
| 1789 | |
| 1790 | sage: pg = RDFInterpreter().pg |
| 1791 | sage: InstrSpec('add', pg('SS','S'), code='o0 = i0+i1;') |
| 1792 | add: SS->S = 'o0 = i0+i1;' |
| 1793 | sage: instr = InstrSpec('py_call', pg('P[D]S@D', 'S'), code=('This is very complicated. ' + 'blah ' * 30)); instr |
| 1794 | py_call: *->S = 'This is very compli... blah blah blah ' |
| 1795 | sage: instr.name |
| 1796 | 'py_call' |
| 1797 | sage: instr.inputs |
| 1798 | [({MC:py_constants}, {MC:code}, None), ({MC:stack}, None, {MC:code})] |
| 1799 | sage: instr.outputs |
| 1800 | [({MC:stack}, None, None)] |
| 1801 | sage: instr.code |
| 1802 | 'This is very complicated. blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah ' |
| 1803 | sage: instr.parameters |
| 1804 | ['py_constants', 'n_inputs'] |
| 1805 | sage: instr.n_inputs |
| 1806 | 0 |
| 1807 | sage: instr.n_outputs |
| 1808 | 1 |
| 1809 | """ |
| 1810 | self.name = name |
| 1811 | self.inputs = io[0] |
| 1812 | self.outputs = io[1] |
| 1813 | self.uses_error_handler = uses_error_handler |
| 1814 | self.handles_own_decref = handles_own_decref |
| 1815 | if code is not None: |
| 1816 | self.code = code |
| 1817 | # XXX We assume that there is only one stack |
| 1818 | n_inputs = 0 |
| 1819 | n_outputs = 0 |
| 1820 | in_effect = '' |
| 1821 | out_effect = '' |
| 1822 | p = [] |
| 1823 | for (ch, addr, len) in self.inputs: |
| 1824 | if ch.is_stack(): |
| 1825 | if len is None: |
| 1826 | n_inputs += 1 |
| 1827 | in_effect += 'S' |
| 1828 | elif isinstance(len, (int, long)): |
| 1829 | n_inputs += len |
| 1830 | in_effect += 'S%d' % len |
| 1831 | else: |
| 1832 | p.append('n_inputs') |
| 1833 | in_effect += '*' |
| 1834 | else: |
| 1835 | p.append(ch.name) |
| 1836 | for (ch, addr, len) in self.outputs: |
| 1837 | if ch.is_stack(): |
| 1838 | if len is None: |
| 1839 | n_outputs += 1 |
| 1840 | out_effect += 'S' |
| 1841 | elif isinstance(len, (int, long)): |
| 1842 | n_outputs += len |
| 1843 | out_effect += 'S%d' % len |
| 1844 | else: |
| 1845 | p.append('n_outputs') |
| 1846 | out_effect += '*' |
| 1847 | else: |
| 1848 | p.append(ch.name) |
| 1849 | self.parameters = p |
| 1850 | self.n_inputs = n_inputs |
| 1851 | self.n_outputs = n_outputs |
| 1852 | self.in_effect = in_effect |
| 1853 | self.out_effect = out_effect |
| 1854 | |
| 1855 | def __repr__(self): |
| 1856 | r""" |
| 1857 | Produce a string representing a given instruction, consisting |
| 1858 | of its name, a brief stack specification, and its code |
| 1859 | (possibly abbreviated). |
| 1860 | |
| 1861 | EXAMPLES: |
| 1862 | sage: from sage.ext.gen_interpreters import * |
| 1863 | sage: pg = RDFInterpreter().pg |
| 1864 | sage: InstrSpec('add', pg('SS','S'), code='o0 = i0+i1;') |
| 1865 | add: SS->S = 'o0 = i0+i1;' |
| 1866 | """ |
| 1867 | rcode = repr(self.code) |
| 1868 | if len(rcode) > 40: |
| 1869 | rcode = rcode[:20] + '...' + rcode[-17:] |
| 1870 | return '%s: %s->%s = %s' % \ |
| 1871 | (self.name, self.in_effect, self.out_effect, rcode) |
| 1872 | |
| 1873 | # Now we have a series of helper functions that make it slightly easier |
| 1874 | # to create instructions. |
| 1875 | |
| 1876 | def instr_infix(name, io, op): |
| 1877 | r""" |
| 1878 | A helper function for creating instructions implemented by |
| 1879 | a single infix binary operator. |
| 1880 | |
| 1881 | EXAMPLES: |
| 1882 | sage: from sage.ext.gen_interpreters import * |
| 1883 | sage: pg = RDFInterpreter().pg |
| 1884 | sage: instr_infix('mul', pg('SS', 'S'), '*') |
| 1885 | mul: SS->S = 'o0 = i0 * i1;' |
| 1886 | """ |
| 1887 | return InstrSpec(name, io, code='o0 = i0 %s i1;' % op) |
| 1888 | |
| 1889 | def instr_funcall_2args(name, io, op): |
| 1890 | r""" |
| 1891 | A helper function for creating instructions implemented by |
| 1892 | a two-argument function call. |
| 1893 | |
| 1894 | EXAMPLES: |
| 1895 | sage: from sage.ext.gen_interpreters import * |
| 1896 | sage: pg = RDFInterpreter().pg |
| 1897 | sage: instr_funcall_2args('atan2', pg('SS', 'S'), 'atan2') |
| 1898 | atan2: SS->S = 'o0 = atan2(i0, i1);' |
| 1899 | """ |
| 1900 | return InstrSpec(name, io, code='o0 = %s(i0, i1);' % op) |
| 1901 | |
| 1902 | def instr_unary(name, io, op): |
| 1903 | r""" |
| 1904 | A helper function for creating instructions with one input |
| 1905 | and one output. |
| 1906 | |
| 1907 | EXAMPLES: |
| 1908 | sage: from sage.ext.gen_interpreters import * |
| 1909 | sage: pg = RDFInterpreter().pg |
| 1910 | sage: instr_unary('sin', pg('S','S'), 'sin(i0)') |
| 1911 | sin: S->S = 'o0 = sin(i0);' |
| 1912 | sage: instr_unary('neg', pg('S','S'), '-i0') |
| 1913 | neg: S->S = 'o0 = -i0;' |
| 1914 | """ |
| 1915 | return InstrSpec(name, io, code='o0 = ' + op + ';') |
| 1916 | |
| 1917 | def instr_funcall_2args_mpfr(name, io, op): |
| 1918 | r""" |
| 1919 | A helper function for creating MPFR instructions with two inputs |
| 1920 | and one output. |
| 1921 | |
| 1922 | EXAMPLES: |
| 1923 | sage: from sage.ext.gen_interpreters import * |
| 1924 | sage: pg = RRInterpreter().pg |
| 1925 | sage: instr_funcall_2args_mpfr('add', pg('SS','S'), 'mpfr_add') |
| 1926 | add: SS->S = 'mpfr_add(o0, i0, i1, GMP_RNDN);' |
| 1927 | """ |
| 1928 | return InstrSpec(name, io, code='%s(o0, i0, i1, GMP_RNDN);' % op) |
| 1929 | |
| 1930 | def instr_funcall_1arg_mpfr(name, io, op): |
| 1931 | r""" |
| 1932 | A helper function for creating MPFR instructions with one input |
| 1933 | and one output. |
| 1934 | |
| 1935 | EXAMPLES: |
| 1936 | sage: from sage.ext.gen_interpreters import * |
| 1937 | sage: pg = RRInterpreter().pg |
| 1938 | sage: instr_funcall_1arg_mpfr('exp', pg('S','S'), 'mpfr_exp') |
| 1939 | exp: S->S = 'mpfr_exp(o0, i0, GMP_RNDN);' |
| 1940 | """ |
| 1941 | return InstrSpec(name, io, code='%s(o0, i0, GMP_RNDN);' % op) |
| 1942 | |
| 1943 | class InterpreterSpec(object): |
| 1944 | r""" |
| 1945 | Each interpreter to be generated by this module is represented |
| 1946 | by an InterpreterSpec. |
| 1947 | """ |
| 1948 | |
| 1949 | def __init__(self): |
| 1950 | r""" |
| 1951 | Initialize an InterpreterSpec. |
| 1952 | |
| 1953 | Initializes the following fields: |
| 1954 | |
| 1955 | header -- a code snippet to go at the top of the C interpreter |
| 1956 | source file |
| 1957 | pyx_header -- a code snippet to go at the top of the wrapper |
| 1958 | class source file |
| 1959 | err_return -- a string indicating the value to be returned |
| 1960 | in case of a Python exception |
| 1961 | mc_code -- a memory chunk to use for the interpreted code |
| 1962 | |
| 1963 | EXAMPLES: |
| 1964 | sage: from sage.ext.gen_interpreters import * |
| 1965 | sage: interp = RDFInterpreter() |
| 1966 | sage: interp.header |
| 1967 | '' |
| 1968 | sage: interp.pyx_header |
| 1969 | '' |
| 1970 | sage: interp.err_return |
| 1971 | '-1094648009105371' |
| 1972 | sage: interp.mc_code |
| 1973 | {MC:code} |
| 1974 | """ |
| 1975 | self.header = '' |
| 1976 | self.pyx_header = '' |
| 1977 | self.err_return = 'NULL' |
| 1978 | self.mc_code = MemoryChunkConstants('code', ty_int) |
| 1979 | |
| 1980 | def _set_opcodes(self): |
| 1981 | r""" |
| 1982 | Assign opcodes to the instructions in this interpreter. |
| 1983 | |
| 1984 | Must be called at the end of __init__ by any subclass of |
| 1985 | InterpreterSpec. |
| 1986 | |
| 1987 | EXAMPLES: |
| 1988 | sage: from sage.ext.gen_interpreters import * |
| 1989 | sage: interp = RDFInterpreter() |
| 1990 | sage: interp.instr_descs[5].opcode |
| 1991 | 5 |
| 1992 | """ |
| 1993 | for i in range(len(self.instr_descs)): |
| 1994 | self.instr_descs[i].opcode = i |
| 1995 | |
| 1996 | |
| 1997 | class StackInterpreter(InterpreterSpec): |
| 1998 | r""" |
| 1999 | A subclass of InterpreterSpec, specialized for stack-based |
| 2000 | interpreters. (Currently all interpreters are stack-based.) |
| 2001 | """ |
| 2002 | |
| 2003 | def __init__(self, type, mc_retval=None): |
| 2004 | r""" |
| 2005 | Initialize a StackInterpreter. |
| 2006 | |
| 2007 | INPUTS: |
| 2008 | type -- A StorageType; the basic type that this interpreter |
| 2009 | operates on |
| 2010 | mc_retval -- default None; if not None, a special-purpose |
| 2011 | MemoryChunk to use as a return value |
| 2012 | |
| 2013 | Initializes the fields described in the documentation for |
| 2014 | InterpreterSpec.__init__, as well as the following: |
| 2015 | |
| 2016 | mc_args, mc_constants, mc_stack -- MemoryChunk values |
| 2017 | return_type -- the type returned by the C interpreter (None for int, |
| 2018 | where 1 means success and 0 means error) |
| 2019 | mc_retval -- None, or the MemoryChunk to use as a return value |
| 2020 | |
| 2021 | EXAMPLES: |
| 2022 | sage: from sage.ext.gen_interpreters import * |
| 2023 | sage: rdf = RDFInterpreter() |
| 2024 | sage: rr = RRInterpreter() |
| 2025 | sage: rdf.mc_args |
| 2026 | {MC:args} |
| 2027 | sage: rdf.mc_constants |
| 2028 | {MC:constants} |
| 2029 | sage: rdf.mc_stack |
| 2030 | {MC:stack} |
| 2031 | sage: rr.mc_retval |
| 2032 | {MC:retval} |
| 2033 | sage: rr.return_type is None |
| 2034 | True |
| 2035 | sage: rdf.return_type.type |
| 2036 | 'double' |
| 2037 | """ |
| 2038 | InterpreterSpec.__init__(self) |
| 2039 | self.mc_args = MemoryChunkArguments('args', type) |
| 2040 | self.mc_constants = MemoryChunkConstants('constants', type) |
| 2041 | self.mc_stack = MemoryChunkScratch('stack', type, is_stack=True) |
| 2042 | if isinstance(type, StorageTypeAssignable): |
| 2043 | self.return_type = type |
| 2044 | else: |
| 2045 | self.return_type = None |
| 2046 | self.mc_retval = mc_retval |
| 2047 | |
| 2048 | class RDFInterpreter(StackInterpreter): |
| 2049 | r""" |
| 2050 | A subclass of StackInterpreter, specifying an interpreter over |
| 2051 | machine-floating-point values (C doubles). |
| 2052 | """ |
| 2053 | |
| 2054 | def __init__(self): |
| 2055 | r""" |
| 2056 | Initialize an RDFInterpreter. |
| 2057 | |
| 2058 | EXAMPLES: |
| 2059 | sage: from sage.ext.gen_interpreters import * |
| 2060 | sage: interp = RDFInterpreter() |
| 2061 | sage: interp.name |
| 2062 | 'rdf' |
| 2063 | sage: interp.mc_py_constants |
| 2064 | {MC:py_constants} |
| 2065 | sage: interp.chunks |
| 2066 | [{MC:args}, {MC:constants}, {MC:py_constants}, {MC:stack}, {MC:code}] |
| 2067 | sage: interp.pg('A[D]', 'S') |
| 2068 | ([({MC:args}, {MC:code}, None)], [({MC:stack}, None, None)]) |
| 2069 | sage: instrs = dict([(ins.name, ins) for ins in interp.instr_descs]) |
| 2070 | sage: instrs['add'] |
| 2071 | add: SS->S = 'o0 = i0 + i1;' |
| 2072 | sage: instrs['py_call'] |
| 2073 | py_call: *->S = ' \nPyObject *py_arg...goto error;\n}\n' |
| 2074 | """ |
| 2075 | |
| 2076 | StackInterpreter.__init__(self, ty_double) |
| 2077 | self.name = 'rdf' |
| 2078 | self.mc_py_constants = MemoryChunkConstants('py_constants', ty_python) |
| 2079 | # This is a randomly chosen number. Whenever this number is |
| 2080 | # returned, the wrapper has to check whether an exception actually |
| 2081 | # happened, so if an expression evaluates to this number execution |
| 2082 | # is slightly slower. Hopefully that won't happen too often :) |
| 2083 | self.err_return = '-1094648009105371' |
| 2084 | self.chunks = [self.mc_args, self.mc_constants, self.mc_py_constants, |
| 2085 | self.mc_stack, |
| 2086 | self.mc_code] |
| 2087 | pg = params_gen(A=self.mc_args, C=self.mc_constants, D=self.mc_code, |
| 2088 | S=self.mc_stack, P=self.mc_py_constants) |
| 2089 | self.pg = pg |
| 2090 | instrs = [ |
| 2091 | InstrSpec('load_arg', pg('A[D]', 'S'), |
| 2092 | code='o0 = i0;'), |
| 2093 | InstrSpec('load_const', pg('C[D]', 'S'), |
| 2094 | code='o0 = i0;'), |
| 2095 | InstrSpec('return', pg('S', ''), |
| 2096 | code='return i0;'), |
| 2097 | InstrSpec('py_call', pg('P[D]S@D', 'S'), |
| 2098 | uses_error_handler=True, |
| 2099 | code=""" |
| 2100 | PyObject *py_args = PyTuple_New(n_i1); |
| 2101 | if (py_args == NULL) goto error; |
| 2102 | int i; |
| 2103 | for (i = 0; i < n_i1; i++) { |
| 2104 | PyObject *arg = PyFloat_FromDouble(i1[i]); |
| 2105 | if (arg == NULL) { |
| 2106 | Py_DECREF(py_args); |
| 2107 | goto error; |
| 2108 | } |
| 2109 | PyTuple_SET_ITEM(py_args, i, arg); |
| 2110 | } |
| 2111 | PyObject *result = PyObject_CallObject(i0, py_args); |
| 2112 | Py_DECREF(py_args); |
| 2113 | if (result == NULL) goto error; |
| 2114 | /* If result is not a float, then this will turn it into a float first. */ |
| 2115 | o0 = PyFloat_AsDouble(result); |
| 2116 | Py_DECREF(result); |
| 2117 | if (o0 == -1 && PyErr_Occurred()) { |
| 2118 | goto error; |
| 2119 | } |
| 2120 | """) |
| 2121 | ] |
| 2122 | for (name, op) in [('add', '+'), ('sub', '-'), |
| 2123 | ('mul', '*'), ('div', '/')]: |
| 2124 | instrs.append(instr_infix(name, pg('SS', 'S'), op)) |
| 2125 | instrs.append(instr_funcall_2args('pow', pg('SS', 'S'), 'pow')) |
| 2126 | for (name, op) in [('neg', '-i0'), ('invert', '1/i0'), |
| 2127 | ('abs', 'fabs(i0)')]: |
| 2128 | instrs.append(instr_unary(name, pg('S', 'S'), op)) |
| 2129 | for name in ['sqrt', 'ceil', 'floor', 'sin', 'cos', 'tan', |
| 2130 | 'asin', 'acos', 'atan', 'sinh', 'cosh', 'tanh', |
| 2131 | 'asinh', 'acosh', 'atanh', 'exp', 'log']: |
| 2132 | instrs.append(instr_unary(name, pg('S', 'S'), "%s(i0)" % name)) |
| 2133 | self.instr_descs = instrs |
| 2134 | self._set_opcodes() |
| 2135 | |
| 2136 | class RRInterpreter(StackInterpreter): |
| 2137 | r""" |
| 2138 | A subclass of StackInterpreter, specifying an interpreter over |
| 2139 | MPFR arbitrary-precision floating-point numbers. |
| 2140 | """ |
| 2141 | |
| 2142 | def __init__(self): |
| 2143 | r""" |
| 2144 | Initialize an RDFInterpreter. |
| 2145 | |
| 2146 | EXAMPLES: |
| 2147 | sage: from sage.ext.gen_interpreters import * |
| 2148 | sage: interp = RRInterpreter() |
| 2149 | sage: interp.name |
| 2150 | 'rr' |
| 2151 | sage: interp.mc_py_constants |
| 2152 | {MC:py_constants} |
| 2153 | sage: interp.chunks |
| 2154 | [{MC:args}, {MC:retval}, {MC:constants}, {MC:py_constants}, {MC:stack}, {MC:code}, {MC:domain}] |
| 2155 | sage: interp.pg('A[D]', 'S') |
| 2156 | ([({MC:args}, {MC:code}, None)], [({MC:stack}, None, None)]) |
| 2157 | sage: instrs = dict([(ins.name, ins) for ins in interp.instr_descs]) |
| 2158 | sage: instrs['add'] |
| 2159 | add: SS->S = 'mpfr_add(o0, i0, i1, GMP_RNDN);' |
| 2160 | sage: instrs['py_call'] |
| 2161 | py_call: *->S = '\nif (!rr_py_call_h...goto error;\n}\n' |
| 2162 | |
| 2163 | That py_call instruction is particularly interesting, and |
| 2164 | demonstrates a useful technique to let you use Cython code |
| 2165 | in an interpreter. Let's look more closely: |
| 2166 | |
| 2167 | sage: print instrs['py_call'].code |
| 2168 | if (!rr_py_call_helper(domain, i0, n_i1, i1, o0)) { |
| 2169 | goto error; |
| 2170 | } |
| 2171 | |
| 2172 | This instruction makes use of the function rr_py_call_helper, |
| 2173 | which is declared... |
| 2174 | |
| 2175 | sage: print interp.header |
| 2176 | #include <mpfr.h> |
| 2177 | #include "wrapper_rr.h" |
| 2178 | |
| 2179 | in wrapper_rr.h. This file is automatically generated by Cython |
| 2180 | from wrapper_rr.pyx, which is automatically generated from |
| 2181 | this spec; in particular, rr_py_call_helper comes from: |
| 2182 | |
| 2183 | sage: print interp.pyx_header |
| 2184 | from ... |
| 2185 | cdef public bint rr_py_call_helper(object domain, object fn, |
| 2186 | int n_args, |
| 2187 | mpfr_t* args, mpfr_t* retval) except 0: |
| 2188 | py_args = [] |
| 2189 | cdef int i |
| 2190 | cdef RealNumber rn |
| 2191 | for i from 0 <= i < n_args: |
| 2192 | rn = domain() |
| 2193 | mpfr_set(rn.value, args[i], GMP_RNDN) |
| 2194 | py_args.append(rn) |
| 2195 | cdef RealNumber result = domain(fn(*py_args)) |
| 2196 | mpfr_set(retval[0], result.value, GMP_RNDN) |
| 2197 | return 1 |
| 2198 | |
| 2199 | |
| 2200 | So instructions where you need to interact with Python can |
| 2201 | call back into Cython code fairly easily. |
| 2202 | """ |
| 2203 | |
| 2204 | StackInterpreter.__init__(self, ty_mpfr, mc_retval= MemoryChunkRRRetval('retval', ty_mpfr)) |
| 2205 | self.name = 'rr' |
| 2206 | self.err_return = '0' |
| 2207 | self.mc_py_constants = MemoryChunkConstants('py_constants', ty_python) |
| 2208 | self.mc_domain = MemoryChunkPyConstant('domain') |
| 2209 | self.chunks = [self.mc_args, self.mc_retval, self.mc_constants, |
| 2210 | self.mc_py_constants, |
| 2211 | self.mc_stack, self.mc_code, self.mc_domain] |
| 2212 | pg = params_gen(A=self.mc_args, C=self.mc_constants, D=self.mc_code, |
| 2213 | S=self.mc_stack, |
| 2214 | P=self.mc_py_constants) |
| 2215 | self.pg = pg |
| 2216 | self.header = """ |
| 2217 | #include <mpfr.h> |
| 2218 | #include "wrapper_rr.h" |
| 2219 | """ |
| 2220 | self.pyx_header = """ |
| 2221 | from sage.rings.real_mpfr cimport RealField, RealNumber |
| 2222 | from sage.libs.mpfr cimport * |
| 2223 | |
| 2224 | cdef public bint rr_py_call_helper(object domain, object fn, |
| 2225 | int n_args, |
| 2226 | mpfr_t* args, mpfr_t* retval) except 0: |
| 2227 | py_args = [] |
| 2228 | cdef int i |
| 2229 | cdef RealNumber rn |
| 2230 | for i from 0 <= i < n_args: |
| 2231 | rn = domain() |
| 2232 | mpfr_set(rn.value, args[i], GMP_RNDN) |
| 2233 | py_args.append(rn) |
| 2234 | cdef RealNumber result = domain(fn(*py_args)) |
| 2235 | mpfr_set(retval[0], result.value, GMP_RNDN) |
| 2236 | return 1 |
| 2237 | |
| 2238 | """[1:] |
| 2239 | instrs = [ |
| 2240 | InstrSpec('load_arg', pg('A[D]', 'S'), |
| 2241 | code='mpfr_set(o0, i0, GMP_RNDN);'), |
| 2242 | InstrSpec('load_const', pg('C[D]', 'S'), |
| 2243 | code='mpfr_set(o0, i0, GMP_RNDN);'), |
| 2244 | InstrSpec('return', pg('S', ''), |
| 2245 | code='mpfr_set(retval[0], i0, GMP_RNDN);\nreturn 1;\n'), |
| 2246 | InstrSpec('py_call', pg('P[D]S@D', 'S'), |
| 2247 | uses_error_handler=True, |
| 2248 | code=""" |
| 2249 | if (!rr_py_call_helper(domain, i0, n_i1, i1, o0)) { |
| 2250 | goto error; |
| 2251 | } |
| 2252 | """) |
| 2253 | ] |
| 2254 | for (name, op) in [('add', 'mpfr_add'), ('sub', 'mpfr_sub'), |
| 2255 | ('mul', 'mpfr_mul'), ('div', 'mpfr_div'), |
| 2256 | ('pow', 'mpfr_pow')]: |
| 2257 | instrs.append(instr_funcall_2args_mpfr(name, pg('SS', 'S'), op)) |
| 2258 | for name in ['neg', 'abs', |
| 2259 | 'log', 'log2', 'log10', |
| 2260 | 'exp', 'exp2', 'exp10', |
| 2261 | 'cos', 'sin', 'tan', |
| 2262 | 'sec', 'csc', 'cot', |
| 2263 | 'acos', 'asin', 'atan', |
| 2264 | 'cosh', 'sinh', 'tanh', |
| 2265 | 'sech', 'csch', 'coth', |
| 2266 | 'acosh', 'asinh', 'atanh', |
| 2267 | 'log1p', 'expm1', 'eint', |
| 2268 | 'gamma', 'lngamma', |
| 2269 | 'zeta', 'erf', 'erfc', |
| 2270 | 'j0', 'j1', 'y0', 'y1']: |
| 2271 | instrs.append(instr_funcall_1arg_mpfr(name, pg('S', 'S'), 'mpfr_' + name)) |
| 2272 | # mpfr_ui_div constructs a temporary mpfr_t and then calls mpfr_div; |
| 2273 | # it would probably be (slightly) faster to use a permanent copy |
| 2274 | # of "one" (on the other hand, the constructed temporary copy is |
| 2275 | # on the stack, so it's very likely to be in the cache). |
| 2276 | instrs.append(InstrSpec('invert', pg('S', 'S'), |
| 2277 | code='mpfr_ui_div(o0, 1, i0, GMP_RNDN);')) |
| 2278 | self.instr_descs = instrs |
| 2279 | self._set_opcodes() |
| 2280 | |
| 2281 | class PythonInterpreter(StackInterpreter): |
| 2282 | r""" |
| 2283 | A subclass of StackInterpreter, specifying an interpreter over |
| 2284 | Python objects. |
| 2285 | |
| 2286 | Let's discuss how the reference-counting works in Python-object |
| 2287 | based interpreters. |
| 2288 | |
| 2289 | There is a simple rule to remember: when executing the code |
| 2290 | snippets, the input variables contain borrowed references; |
| 2291 | you must fill in the output variables with references you own. |
| 2292 | |
| 2293 | As an optimization, an instruction may set .handles_own_decref; in |
| 2294 | that case, it must decref any input variables that came from the |
| 2295 | stack. (Input variables that came from arguments/constants chunks |
| 2296 | must NOT be decref'ed!) In addition, with .handles_own_decref, if |
| 2297 | any of your input variables are arbitrary-count, then you must |
| 2298 | NULL out these variables as you decref them. (Use Py_CLEAR to do |
| 2299 | this, unless you understand the documentation of Py_CLEAR and why |
| 2300 | it's different than Py_XDECREF followed by assigning NULL.) |
| 2301 | |
| 2302 | Note that as a tiny optimization, the interpreter always assumes |
| 2303 | (and assures) that empty parts of the stack contain NULL, so |
| 2304 | it doesn't bother to Py_XDECREF before it pushes onto the stack. |
| 2305 | """ |
| 2306 | |
| 2307 | def __init__(self): |
| 2308 | r""" |
| 2309 | Initialize a PythonInterpreter. |
| 2310 | |
| 2311 | EXAMPLES: |
| 2312 | sage: from sage.ext.gen_interpreters import * |
| 2313 | sage: interp = PythonInterpreter() |
| 2314 | sage: interp.name |
| 2315 | 'py' |
| 2316 | sage: interp.mc_args |
| 2317 | {MC:args} |
| 2318 | sage: interp.chunks |
| 2319 | [{MC:args}, {MC:constants}, {MC:stack}, {MC:code}] |
| 2320 | sage: instrs = dict([(ins.name, ins) for ins in interp.instr_descs]) |
| 2321 | sage: instrs['add'] |
| 2322 | add: SS->S = 'o0 = PyNumber_Add(i0, i1);' |
| 2323 | sage: instrs['py_call'] |
| 2324 | py_call: *->S = '\nPyObject *py_args...CREF(py_args);\n' |
| 2325 | """ |
| 2326 | |
| 2327 | StackInterpreter.__init__(self, ty_python) |
| 2328 | self.name = 'py' |
| 2329 | # StackInterpreter.__init__ gave us a MemoryChunkArguments. |
| 2330 | # Override with MemoryChunkPythonArguments. |
| 2331 | self.mc_args = MemoryChunkPythonArguments('args', ty_python) |
| 2332 | self.chunks = [self.mc_args, self.mc_constants, self.mc_stack, |
| 2333 | self.mc_code] |
| 2334 | pg = params_gen(A=self.mc_args, C=self.mc_constants, D=self.mc_code, |
| 2335 | S=self.mc_stack) |
| 2336 | self.pg = pg |
| 2337 | self.header = """ |
| 2338 | #include <Python.h> |
| 2339 | #define CHECK(x) (x != NULL) |
| 2340 | """ |
| 2341 | instrs = [ |
| 2342 | InstrSpec('load_arg', pg('A[D]', 'S'), |
| 2343 | code='o0 = i0; Py_INCREF(o0);'), |
| 2344 | InstrSpec('load_const', pg('C[D]', 'S'), |
| 2345 | code='o0 = i0; Py_INCREF(o0);'), |
| 2346 | InstrSpec('return', pg('S', ''), |
| 2347 | code='return i0;', |
| 2348 | handles_own_decref=True), |
| 2349 | InstrSpec('py_call', pg('C[D]S@D', 'S'), |
| 2350 | handles_own_decref=True, |
| 2351 | code=""" |
| 2352 | PyObject *py_args = PyTuple_New(n_i1); |
| 2353 | if (py_args == NULL) goto error; |
| 2354 | int i; |
| 2355 | for (i = 0; i < n_i1; i++) { |
| 2356 | PyObject *arg = i1[i]; |
| 2357 | PyTuple_SET_ITEM(py_args, i, arg); |
| 2358 | i1[i] = NULL; |
| 2359 | } |
| 2360 | o0 = PyObject_CallObject(i0, py_args); |
| 2361 | Py_DECREF(py_args); |
| 2362 | """) |
| 2363 | ] |
| 2364 | for (name, op) in [('add', 'PyNumber_Add'), |
| 2365 | ('sub', 'PyNumber_Subtract'), |
| 2366 | ('mul', 'PyNumber_Multiply'), |
| 2367 | ('div', 'PyNumber_Divide')]: |
| 2368 | instrs.append(instr_funcall_2args(name, pg('SS', 'S'), op)) |
| 2369 | instrs.append(InstrSpec('pow', pg('SS', 'S'), |
| 2370 | code='o0 = PyNumber_Power(i0, i1, Py_None);')) |
| 2371 | for (name, op) in [('neg', 'PyNumber_Negative'), |
| 2372 | ('invert', 'PyNumber_Invert'), |
| 2373 | ('abs', 'PyNumber_Absolute')]: |
| 2374 | instrs.append(instr_unary(name, pg('S', 'S'), '%s(i0)'%op)) |
| 2375 | self.instr_descs = instrs |
| 2376 | self._set_opcodes() |
| 2377 | |
| 2378 | class ElementInterpreter(PythonInterpreter): |
| 2379 | r""" |
| 2380 | A subclass of PythonInterpreter, specifying an interpreter over |
| 2381 | Sage elements with a particular parent. |
| 2382 | |
| 2383 | This is very similar to the PythonInterpreter, but after every |
| 2384 | instruction, the result is checked to make sure it actually an |
| 2385 | element with the correct parent; if not, we attempt to convert it. |
| 2386 | |
| 2387 | Uses the same instructions (with the same implementation) as |
| 2388 | PythonInterpreter. |
| 2389 | """ |
| 2390 | |
| 2391 | def __init__(self): |
| 2392 | r""" |
| 2393 | Initialize an ElementInterpreter. |
| 2394 | |
| 2395 | EXAMPLES: |
| 2396 | sage: from sage.ext.gen_interpreters import * |
| 2397 | sage: interp = ElementInterpreter() |
| 2398 | sage: interp.name |
| 2399 | 'el' |
| 2400 | sage: interp.mc_args |
| 2401 | {MC:args} |
| 2402 | sage: interp.chunks |
| 2403 | [{MC:args}, {MC:constants}, {MC:stack}, {MC:domain}, {MC:code}] |
| 2404 | sage: instrs = dict([(ins.name, ins) for ins in interp.instr_descs]) |
| 2405 | sage: instrs['add'] |
| 2406 | add: SS->S = 'o0 = PyNumber_Add(i0, i1);' |
| 2407 | sage: instrs['py_call'] |
| 2408 | py_call: *->S = '\nPyObject *py_args...CREF(py_args);\n' |
| 2409 | """ |
| 2410 | |
| 2411 | PythonInterpreter.__init__(self) |
| 2412 | self.name = 'el' |
| 2413 | # PythonInterpreter.__init__ gave us a MemoryChunkPythonArguments. |
| 2414 | # Override with MemoryChunkElementArguments. |
| 2415 | self.mc_args = MemoryChunkElementArguments('args', ty_python) |
| 2416 | self.mc_domain_info = MemoryChunkPyConstant('domain') |
| 2417 | self.chunks = [self.mc_args, self.mc_constants, self.mc_stack, |
| 2418 | self.mc_domain_info, self.mc_code] |
| 2419 | self.header = """ |
| 2420 | #include <Python.h> |
| 2421 | #include "wrapper_el.h" |
| 2422 | |
| 2423 | #define CHECK(x) do_check(&(x), domain) |
| 2424 | |
| 2425 | static inline int do_check(PyObject **x, PyObject *domain) { |
| 2426 | if (*x == NULL) return 0; |
| 2427 | PyObject *new_x = el_check_element(*x, domain); |
| 2428 | Py_DECREF(*x); |
| 2429 | *x = new_x; |
| 2430 | if (*x == NULL) return 0; |
| 2431 | return 1; |
| 2432 | } |
| 2433 | """ |
| 2434 | self.pyx_header = """ |
| 2435 | from sage.structure.element cimport Element |
| 2436 | |
| 2437 | cdef public object el_check_element(object v, parent): |
| 2438 | cdef Element v_el |
| 2439 | |
| 2440 | if PY_TYPE_CHECK(v, Element): |
| 2441 | v_el = <Element>v |
| 2442 | if v_el._parent is parent: |
| 2443 | return v_el |
| 2444 | |
| 2445 | return parent(v) |
| 2446 | |
| 2447 | """[1:] |
| 2448 | |
| 2449 | class InterpreterGenerator(object): |
| 2450 | r""" |
| 2451 | This class takes an InterpreterSpec and generates the corresponding |
| 2452 | C interpreter and Cython wrapper. |
| 2453 | |
| 2454 | See the documentation for methods get_wrapper and get_interpreter |
| 2455 | for more information. |
| 2456 | """ |
| 2457 | |
| 2458 | def __init__(self, spec): |
| 2459 | r""" |
| 2460 | Initialize an InterpreterGenerator. |
| 2461 | |
| 2462 | INPUTS: |
| 2463 | spec -- an InterpreterSpec |
| 2464 | |
| 2465 | EXAMPLES: |
| 2466 | sage: from sage.ext.gen_interpreters import * |
| 2467 | sage: interp = RDFInterpreter() |
| 2468 | sage: gen = InterpreterGenerator(interp) |
| 2469 | sage: gen._spec is interp |
| 2470 | True |
| 2471 | sage: gen.uses_error_handler |
| 2472 | False |
| 2473 | """ |
| 2474 | |
| 2475 | self._spec = spec |
| 2476 | self.uses_error_handler = False |
| 2477 | |
| 2478 | def gen_code(self, instr_desc, write): |
| 2479 | r""" |
| 2480 | Generates code for a single instruction. |
| 2481 | |
| 2482 | INPUTS: |
| 2483 | instr_desc -- an InstrSpec |
| 2484 | write -- a Python callable |
| 2485 | |
| 2486 | This function calls its write parameter successively with |
| 2487 | strings; when these strings are concatenated, the result is |
| 2488 | the code for the given instruction. |
| 2489 | |
| 2490 | See the documentation for the get_interpreter method for more |
| 2491 | information. |
| 2492 | |
| 2493 | EXAMPLES: |
| 2494 | sage: from sage.ext.gen_interpreters import * |
| 2495 | sage: interp = RDFInterpreter() |
| 2496 | sage: gen = InterpreterGenerator(interp) |
| 2497 | sage: import cStringIO |
| 2498 | sage: buff = cStringIO.StringIO() |
| 2499 | sage: instrs = dict([(ins.name, ins) for ins in interp.instr_descs]) |
| 2500 | sage: gen.gen_code(instrs['div'], buff.write) |
| 2501 | sage: print buff.getvalue() |
| 2502 | case 7: /* div */ |
| 2503 | { |
| 2504 | double i1 = *--stack; |
| 2505 | double i0 = *--stack; |
| 2506 | double o0; |
| 2507 | o0 = i0 / i1; |
| 2508 | *stack++ = o0; |
| 2509 | } |
| 2510 | break; |
| 2511 | <BLANKLINE> |
| 2512 | """ |
| 2513 | |
| 2514 | d = instr_desc |
| 2515 | w = write |
| 2516 | s = self._spec |
| 2517 | |
| 2518 | if d.uses_error_handler: |
| 2519 | self.uses_error_handler = True |
| 2520 | |
| 2521 | w(je(""" |
| 2522 | case {{ d.opcode }}: /* {{ d.name }} */ |
| 2523 | { |
| 2524 | """, d=d)) |
| 2525 | |
| 2526 | # If the inputs to an instruction come from the stack, |
| 2527 | # then we want to generate code for the inputs in reverse order: |
| 2528 | # for instance, the divide instruction, which takes inputs A and B |
| 2529 | # and generates A/B, needs to pop B off the stack first. |
| 2530 | # On the other hand, if the inputs come from the constant pool, |
| 2531 | # then we want to generate code for the inputs in normal order, |
| 2532 | # because the addresses in the code stream will be in that order. |
| 2533 | # We handle this by running through the inputs in two passes: |
| 2534 | # first a forward pass, where we handle non-stack inputs |
| 2535 | # (and lengths for stack inputs), and then a reverse pass, |
| 2536 | # where we handle stack inputs. |
| 2537 | for i in range(len(d.inputs)): |
| 2538 | (ch, addr, input_len) = d.inputs[i] |
| 2539 | chst = ch.storage_type |
| 2540 | if addr is not None: |
| 2541 | w(" int ai%d = %s;\n" % (i, string_of_addr(addr))) |
| 2542 | if input_len is not None: |
| 2543 | w(" int n_i%d = %s;\n" % (i, string_of_addr(input_len))) |
| 2544 | if not ch.is_stack(): |
| 2545 | if input_len is not None: |
| 2546 | w(" %s i%d = %s + ai%d;\n" % |
| 2547 | (chst.c_ptr_type(), i, ch.name, i)) |
| 2548 | else: |
| 2549 | w(" %s i%d = %s[ai%d];\n" % |
| 2550 | (chst.c_local_type(), i, ch.name, i)) |
| 2551 | |
| 2552 | for i in reversed(range(len(d.inputs))): |
| 2553 | (ch, addr, input_len) = d.inputs[i] |
| 2554 | chst = ch.storage_type |
| 2555 | if ch.is_stack(): |
| 2556 | if input_len is not None: |
| 2557 | w(" %s -= n_i%d;\n" % (ch.name, i)) |
| 2558 | w(" %s i%d = %s;\n" % (chst.c_ptr_type(), i, ch.name)) |
| 2559 | else: |
| 2560 | w(" %s i%d = *--%s;\n" % (chst.c_local_type(), i, ch.name)) |
| 2561 | if ch.is_python_refcounted_stack(): |
| 2562 | w(" *%s = NULL;\n" % ch.name) |
| 2563 | |
| 2564 | for i in range(len(d.outputs)): |
| 2565 | (ch, addr, output_len) = d.outputs[i] |
| 2566 | chst = ch.storage_type |
| 2567 | if addr is not None: |
| 2568 | w(" int ao%d = %s;\n" % (i, string_of_addr(addr))) |
| 2569 | if output_len is not None: |
| 2570 | w(" int n_o%d = %s;\n" % (i, string_of_addr(output_len))) |
| 2571 | if ch.is_stack(): |
| 2572 | w(" %s o%d = %s;\n" % |
| 2573 | (chst.c_ptr_type(), i, ch.name)) |
| 2574 | w(" %s += n_o%d;\n" % (ch.name, i)) |
| 2575 | else: |
| 2576 | w(" %s o%d = %s + ao%d;\n" % |
| 2577 | (chst.c_ptr_type(), i, ch.name, i)) |
| 2578 | |
| 2579 | else: |
| 2580 | if not chst.cheap_copies(): |
| 2581 | if ch.is_stack(): |
| 2582 | w(" %s o%d = *%s++;\n" % |
| 2583 | (chst.c_local_type(), i, ch.name)) |
| 2584 | else: |
| 2585 | w(" %s o%d = %s[ao%d];\n" % |
| 2586 | (chst.c_local_type(), i, ch.name, i)) |
| 2587 | else: |
| 2588 | w(" %s o%d;\n" % (chst.c_local_type(), i)) |
| 2589 | |
| 2590 | w(indent_lines(8, d.code.rstrip('\n') + '\n')) |
| 2591 | |
| 2592 | stack_offsets = defaultdict(int) |
| 2593 | for i in range(len(d.inputs)): |
| 2594 | (ch, addr, input_len) = d.inputs[i] |
| 2595 | chst = ch.storage_type |
| 2596 | if ch.is_python_refcounted_stack() and not d.handles_own_decref: |
| 2597 | if input_len is None: |
| 2598 | w(" Py_DECREF(i%d);\n" % i) |
| 2599 | stack_offsets[ch] += 1 |
| 2600 | else: |
| 2601 | w(je(""" |
| 2602 | int {{ iter }}; |
| 2603 | for ({{ iter }} = 0; {{ iter }} < n_i{{ i }}; {{ iter }}++) { |
| 2604 | Py_CLEAR(i{{ i }}[{{ iter }}]); |
| 2605 | } |
| 2606 | """, iter='_interp_iter_%d' % i, i=i)) |
| 2607 | |
| 2608 | for i in range(len(d.outputs)): |
| 2609 | ch = d.outputs[i][0] |
| 2610 | chst = ch.storage_type |
| 2611 | if chst.python_refcounted(): |
| 2612 | # We don't yet support code chunks |
| 2613 | # that produce multiple Python values, because of |
| 2614 | # the way it complicates error handling. |
| 2615 | assert i == 0 |
| 2616 | w(" if (!CHECK(o%d)) {\n" % i) |
| 2617 | w(" Py_XDECREF(o%d);\n" % i) |
| 2618 | w(" goto error;\n") |
| 2619 | w(" }\n") |
| 2620 | self.uses_error_handler = True |
| 2621 | if chst.cheap_copies(): |
| 2622 | if ch.is_stack(): |
| 2623 | w(" *%s++ = o%d;\n" % (ch.name, i)) |
| 2624 | else: |
| 2625 | w(" %s[ao%d] = o%d;\n" % (ch.name, i, i)) |
| 2626 | |
| 2627 | w(je(""" |
| 2628 | } |
| 2629 | break; |
| 2630 | """)) |
| 2631 | |
| 2632 | def func_header(self, cython=False): |
| 2633 | r""" |
| 2634 | Generates the function header for the declaration (in the Cython |
| 2635 | wrapper) or the definition (in the C interpreter) of the interpreter |
| 2636 | function. |
| 2637 | |
| 2638 | EXAMPLES: |
| 2639 | sage: from sage.ext.gen_interpreters import * |
| 2640 | sage: interp = ElementInterpreter() |
| 2641 | sage: gen = InterpreterGenerator(interp) |
| 2642 | sage: print gen.func_header() |
| 2643 | PyObject* interp_el(PyObject** args, |
| 2644 | PyObject** constants, |
| 2645 | PyObject** stack, |
| 2646 | PyObject* domain, |
| 2647 | int* code) |
| 2648 | sage: print gen.func_header(cython=True) |
| 2649 | object interp_el(PyObject** args, |
| 2650 | PyObject** constants, |
| 2651 | PyObject** stack, |
| 2652 | PyObject* domain, |
| 2653 | int* code) |
| 2654 | """ |
| 2655 | s = self._spec |
| 2656 | ret_ty = 'bint' if cython else 'int' |
| 2657 | if s.return_type: |
| 2658 | ret_ty = s.return_type.c_decl_type() |
| 2659 | if cython: |
| 2660 | ret_ty = s.return_type.cython_decl_type() |
| 2661 | return je("""{{ ret_ty }} interp_{{ s.name }}( |
| 2662 | {%- for ch in s.chunks %} |
| 2663 | {% if not loop.first %}, |
| 2664 | {% endif %}{{ ch.declare_parameter() }} |
| 2665 | {%- endfor %})""", ret_ty=ret_ty, s=s) |
| 2666 | |
| 2667 | def write_interpreter(self, write): |
| 2668 | r""" |
| 2669 | Generate the code for the C interpreter. |
| 2670 | |
| 2671 | This function calls its write parameter successively with |
| 2672 | strings; when these strings are concatenated, the result is |
| 2673 | the code for the interpreter. |
| 2674 | |
| 2675 | See the documentation for the get_interpreter method for more |
| 2676 | information. |
| 2677 | |
| 2678 | EXAMPLES: |
| 2679 | sage: from sage.ext.gen_interpreters import * |
| 2680 | sage: interp = RDFInterpreter() |
| 2681 | sage: gen = InterpreterGenerator(interp) |
| 2682 | sage: import cStringIO |
| 2683 | sage: buff = cStringIO.StringIO() |
| 2684 | sage: gen.write_interpreter(buff.write) |
| 2685 | sage: print buff.getvalue() |
| 2686 | /* Automatically generated. Do not edit! */ ... |
| 2687 | """ |
| 2688 | s = self._spec |
| 2689 | w = write |
| 2690 | w(je(""" |
| 2691 | /* Automatically generated. Do not edit! */ |
| 2692 | #include <Python.h> |
| 2693 | {% print s.header %} |
| 2694 | {{ self.func_header() }} { |
| 2695 | while (1) { |
| 2696 | switch (*code++) { |
| 2697 | """, s=s, self=self, i=indent_lines)) |
| 2698 | for instr_desc in s.instr_descs: |
| 2699 | self.gen_code(instr_desc, w) |
| 2700 | w(je(""" |
| 2701 | } |
| 2702 | } |
| 2703 | {% if self.uses_error_handler %} |
| 2704 | error: |
| 2705 | return {{ s.err_return }}; |
| 2706 | {% endif %} |
| 2707 | } |
| 2708 | |
| 2709 | """, s=s, i=indent_lines, self=self)) |
| 2710 | |
| 2711 | def write_wrapper(self, write): |
| 2712 | r""" |
| 2713 | Generate the code for the Cython wrapper. |
| 2714 | This function calls its write parameter successively with |
| 2715 | strings; when these strings are concatenated, the result is |
| 2716 | the code for the interpreter. |
| 2717 | |
| 2718 | See the documentation for the get_wrapper method for more |
| 2719 | information. |
| 2720 | |
| 2721 | EXAMPLES: |
| 2722 | sage: from sage.ext.gen_interpreters import * |
| 2723 | sage: interp = RDFInterpreter() |
| 2724 | sage: gen = InterpreterGenerator(interp) |
| 2725 | sage: import cStringIO |
| 2726 | sage: buff = cStringIO.StringIO() |
| 2727 | sage: gen.write_wrapper(buff.write) |
| 2728 | sage: print buff.getvalue() |
| 2729 | # Automatically generated. Do not edit! ... |
| 2730 | """ |
| 2731 | s = self._spec |
| 2732 | w = write |
| 2733 | types = set() |
| 2734 | do_cleanup = False |
| 2735 | for ch in s.chunks: |
| 2736 | if ch.storage_type is not None: |
| 2737 | types.add(ch.storage_type) |
| 2738 | do_cleanup = do_cleanup or ch.needs_cleanup_on_error() |
| 2739 | for ch in s.chunks: |
| 2740 | if ch.name == 'args': |
| 2741 | arg_ch = ch |
| 2742 | |
| 2743 | the_call = je(""" |
| 2744 | {% if s.return_type %}return {% endif -%} |
| 2745 | interp_{{ s.name }}({{ arg_ch.pass_argument() }} |
| 2746 | {% for ch in s.chunks[1:] %} |
| 2747 | , {{ ch.pass_argument() }} |
| 2748 | {% endfor %} |
| 2749 | ) |
| 2750 | """, s=s, arg_ch=arg_ch) |
| 2751 | |
| 2752 | w(je(""" |
| 2753 | # Automatically generated. Do not edit! |
| 2754 | |
| 2755 | include "../stdsage.pxi" |
| 2756 | from python_object cimport PyObject |
| 2757 | cdef extern from "Python.h": |
| 2758 | void Py_DECREF(PyObject *o) |
| 2759 | void Py_INCREF(PyObject *o) |
| 2760 | void Py_CLEAR(PyObject *o) |
| 2761 | |
| 2762 | cdef extern from "listobject.h": |
| 2763 | object PyList_New(Py_ssize_t len) |
| 2764 | ctypedef struct PyListObject: |
| 2765 | PyObject **ob_item |
| 2766 | |
| 2767 | cdef extern from "tupleobject.h": |
| 2768 | ctypedef struct PyTupleObject: |
| 2769 | PyObject **ob_item |
| 2770 | |
| 2771 | from sage.ext.fast_callable cimport Wrapper |
| 2772 | {% print s.pyx_header %} |
| 2773 | |
| 2774 | cdef extern {{ self.func_header(cython=true) -}} |
| 2775 | {% if s.err_return != 'NULL' %} |
| 2776 | except? {{ s.err_return -}} |
| 2777 | {% endif %} |
| 2778 | |
| 2779 | cdef class Wrapper_{{ s.name }}(Wrapper): |
| 2780 | {% for ty in types %} |
| 2781 | {% print indent_lines(4, ty.class_member_declarations) %} |
| 2782 | {% endfor %} |
| 2783 | {% for ch in s.chunks %} |
| 2784 | {% print ch.declare_class_members() %} |
| 2785 | {% endfor %} |
| 2786 | |
| 2787 | def __init__(self, args): |
| 2788 | Wrapper.__init__(self, args, metadata) |
| 2789 | cdef int i |
| 2790 | cdef int count |
| 2791 | {% for ty in types %} |
| 2792 | {% print indent_lines(8, ty.local_declarations) %} |
| 2793 | {% print indent_lines(8, ty.class_member_initializations) %} |
| 2794 | {% endfor %} |
| 2795 | {% for ch in s.chunks %} |
| 2796 | {% print ch.init_class_members() %} |
| 2797 | {% endfor %} |
| 2798 | |
| 2799 | def __dealloc__(self): |
| 2800 | cdef int i |
| 2801 | {% for ch in s.chunks %} |
| 2802 | {% print ch.dealloc_class_members() %} |
| 2803 | {% endfor %} |
| 2804 | |
| 2805 | def __call__(self, *args): |
| 2806 | if self._n_args != len(args): raise ValueError |
| 2807 | {% for ty in types %} |
| 2808 | {% print indent_lines(8, ty.local_declarations) %} |
| 2809 | {% endfor %} |
| 2810 | {% print indent_lines(8, arg_ch.setup_args()) %} |
| 2811 | {% for ch in s.chunks %} |
| 2812 | {% print ch.declare_call_locals() %} |
| 2813 | {% endfor %} |
| 2814 | {% if do_cleanup %} |
| 2815 | try: |
| 2816 | {% print indent_lines(4, the_call) %} |
| 2817 | except: |
| 2818 | {% for ch in s.chunks %} |
| 2819 | {% if ch.needs_cleanup_on_error() %} |
| 2820 | {% print indent_lines(12, ch.handle_cleanup()) %} |
| 2821 | {% endif %} |
| 2822 | {% endfor %} |
| 2823 | raise |
| 2824 | {% else %} |
| 2825 | {% print the_call %} |
| 2826 | {% endif %} |
| 2827 | {% if not s.return_type %} |
| 2828 | return retval |
| 2829 | {% endif %} |
| 2830 | |
| 2831 | from sage.ext.fast_callable import CompilerInstrSpec, InterpreterMetadata |
| 2832 | metadata = InterpreterMetadata(by_opname={ |
| 2833 | {% for instr in s.instr_descs %} |
| 2834 | '{{ instr.name }}': |
| 2835 | (CompilerInstrSpec({{ instr.n_inputs }}, {{ instr.n_outputs }}, {{ instr.parameters }}), {{ instr.opcode }}), |
| 2836 | {% endfor %} |
| 2837 | }, |
| 2838 | by_opcode=[ |
| 2839 | {% for instr in s.instr_descs %} |
| 2840 | ('{{ instr.name }}', |
| 2841 | CompilerInstrSpec({{ instr.n_inputs }}, {{ instr.n_outputs }}, {{ instr.parameters }})), |
| 2842 | {% endfor %} |
| 2843 | ]) |
| 2844 | """, s=s, self=self, types=types, arg_ch=arg_ch, indent_lines=indent_lines, the_call=the_call, do_cleanup=do_cleanup)) |
| 2845 | |
| 2846 | def get_interpreter(self): |
| 2847 | r""" |
| 2848 | Returns the code for the C interpreter. |
| 2849 | |
| 2850 | EXAMPLES: |
| 2851 | |
| 2852 | First we get the InterpreterSpec for several interpreters: |
| 2853 | sage: from sage.ext.gen_interpreters import * |
| 2854 | sage: rdf_spec = RDFInterpreter() |
| 2855 | sage: rr_spec = RRInterpreter() |
| 2856 | sage: el_spec = ElementInterpreter() |
| 2857 | |
| 2858 | Then we get the actual interpreter code: |
| 2859 | sage: rdf_interp = InterpreterGenerator(rdf_spec).get_interpreter() |
| 2860 | sage: rr_interp = InterpreterGenerator(rr_spec).get_interpreter() |
| 2861 | sage: el_interp = InterpreterGenerator(el_spec).get_interpreter() |
| 2862 | |
| 2863 | Now we can look through these interpreters. |
| 2864 | |
| 2865 | Each interpreter starts with a file header; this can be |
| 2866 | customized on a per-interpreter basis: |
| 2867 | sage: print rr_interp |
| 2868 | /* Automatically generated. Do not edit! */ |
| 2869 | #include <Python.h> |
| 2870 | #include <mpfr.h> |
| 2871 | #include "wrapper_rr.h" |
| 2872 | ... |
| 2873 | |
| 2874 | Next is the function header, with one argument per memory chunk |
| 2875 | in the interpreter spec. |
| 2876 | sage: print el_interp |
| 2877 | /* ... */ ... |
| 2878 | PyObject* interp_el(PyObject** args, |
| 2879 | PyObject** constants, |
| 2880 | PyObject** stack, |
| 2881 | PyObject* domain, |
| 2882 | int* code) { |
| 2883 | ... |
| 2884 | |
| 2885 | Currently, the interpreters have a very simple structure; just |
| 2886 | grab the next instruction and execute it, in a switch |
| 2887 | statement. |
| 2888 | sage: print rdf_interp |
| 2889 | /* ... */ ... |
| 2890 | while (1) { |
| 2891 | switch (*code++) { |
| 2892 | ... |
| 2893 | |
| 2894 | Then comes the code for each instruction. Here is one of the |
| 2895 | simplest instructions: |
| 2896 | sage: print rdf_interp |
| 2897 | /* ... */ ... |
| 2898 | case 9: /* neg */ |
| 2899 | { |
| 2900 | double i0 = *--stack; |
| 2901 | double o0; |
| 2902 | o0 = -i0; |
| 2903 | *stack++ = o0; |
| 2904 | } |
| 2905 | break; |
| 2906 | ... |
| 2907 | |
| 2908 | We simply pull the top of the stack into a variable, negate it, |
| 2909 | and write the result back onto the stack. |
| 2910 | |
| 2911 | Let's look at the MPFR-based version of this instruction. |
| 2912 | This is an example of an interpreter with an auto-reference |
| 2913 | type. |
| 2914 | sage: print rr_interp |
| 2915 | /* ... */ ... |
| 2916 | case 9: /* neg */ |
| 2917 | { |
| 2918 | mpfr_ptr i0 = *--stack; |
| 2919 | mpfr_ptr o0 = *stack++; |
| 2920 | mpfr_neg(o0, i0, GMP_RNDN); |
| 2921 | } |
| 2922 | break; |
| 2923 | ... |
| 2924 | |
| 2925 | Here we see that the input and output variables are actually |
| 2926 | just pointers into the stack. But due to the auto-reference |
| 2927 | trick, the actual code snippet, ``mpfr_net(o0, i0, GMP_RNDN);``, |
| 2928 | is exactly the same as if i0 and o0 were declared as local |
| 2929 | mpfr_t variables. |
| 2930 | |
| 2931 | For completeness, let's look at this instruction in the |
| 2932 | Python-object element interpreter. |
| 2933 | sage: print el_interp |
| 2934 | /* ... */ ... |
| 2935 | case 9: /* neg */ |
| 2936 | { |
| 2937 | PyObject* i0 = *--stack; |
| 2938 | *stack = NULL; |
| 2939 | PyObject* o0; |
| 2940 | o0 = PyNumber_Negative(i0); |
| 2941 | Py_DECREF(i0); |
| 2942 | if (!CHECK(o0)) { |
| 2943 | Py_XDECREF(o0); |
| 2944 | goto error; |
| 2945 | } |
| 2946 | *stack++ = o0; |
| 2947 | } |
| 2948 | break; |
| 2949 | ... |
| 2950 | |
| 2951 | The original code snippet was only ``o0 = PyNumber_Negative(i0);``; |
| 2952 | all the rest is automatically generated. For ElementInterpreter, |
| 2953 | the CHECK macro actually checks for an exception (makes sure that |
| 2954 | o0 is not NULL), tests if the o0 is an element with the correct |
| 2955 | parent, and if not converts it into the correct parent. (That is, |
| 2956 | it can potentially modify the variable o0.) |
| 2957 | """ |
| 2958 | import cStringIO |
| 2959 | buff = cStringIO.StringIO() |
| 2960 | self.write_interpreter(buff.write) |
| 2961 | return buff.getvalue() |
| 2962 | |
| 2963 | def get_wrapper(self): |
| 2964 | r""" |
| 2965 | Returns the code for the Cython wrapper. |
| 2966 | |
| 2967 | EXAMPLES: |
| 2968 | |
| 2969 | First we get the InterpreterSpec for several interpreters: |
| 2970 | sage: from sage.ext.gen_interpreters import * |
| 2971 | sage: rdf_spec = RDFInterpreter() |
| 2972 | sage: rr_spec = RRInterpreter() |
| 2973 | sage: el_spec = ElementInterpreter() |
| 2974 | |
| 2975 | Then we get the actual wrapper code: |
| 2976 | sage: rdf_wrapper = InterpreterGenerator(rdf_spec).get_wrapper() |
| 2977 | sage: rr_wrapper = InterpreterGenerator(rr_spec).get_wrapper() |
| 2978 | sage: el_wrapper = InterpreterGenerator(el_spec).get_wrapper() |
| 2979 | |
| 2980 | Now we can look through these wrappers. |
| 2981 | |
| 2982 | Each wrapper starts with a file header; this can be |
| 2983 | customized on a per-interpreter basis (some blank lines have been |
| 2984 | elided below): |
| 2985 | sage: print rdf_wrapper |
| 2986 | # Automatically generated. Do not edit! |
| 2987 | include "../stdsage.pxi" |
| 2988 | from python_object cimport PyObject |
| 2989 | cdef extern from "Python.h": |
| 2990 | void Py_DECREF(PyObject *o) |
| 2991 | void Py_INCREF(PyObject *o) |
| 2992 | void Py_CLEAR(PyObject *o) |
| 2993 | cdef extern from "listobject.h": |
| 2994 | object PyList_New(Py_ssize_t len) |
| 2995 | ctypedef struct PyListObject: |
| 2996 | PyObject **ob_item |
| 2997 | cdef extern from "tupleobject.h": |
| 2998 | ctypedef struct PyTupleObject: |
| 2999 | PyObject **ob_item |
| 3000 | from sage.ext.fast_callable cimport Wrapper |
| 3001 | ... |
| 3002 | |
| 3003 | Next is the declaration of the C interpreter function. |
| 3004 | sage: print rdf_wrapper |
| 3005 | # ... |
| 3006 | cdef extern double interp_rdf(double* args, |
| 3007 | double* constants, |
| 3008 | PyObject** py_constants, |
| 3009 | double* stack, |
| 3010 | int* code) except? -1094648009105371 |
| 3011 | ... |
| 3012 | |
| 3013 | We need a way to propagate exceptions back to the wrapper, |
| 3014 | even though we only return a double from interp_rdf. The |
| 3015 | ``except? -1094648009105371`` (that's a randomly chosen |
| 3016 | number) means that we will return that number if there's an |
| 3017 | exception, but the wrapper still has to check whether that's a |
| 3018 | legitimate return or an exception. (Cython does this |
| 3019 | automatically.) |
| 3020 | |
| 3021 | Next comes the actual wrapper class, which starts off with |
| 3022 | a list of member declarations. |
| 3023 | sage: print rdf_wrapper |
| 3024 | # ... |
| 3025 | cdef class Wrapper_rdf(Wrapper): |
| 3026 | cdef int _n_args |
| 3027 | cdef double* _args |
| 3028 | cdef int _n_constants |
| 3029 | cdef double* _constants |
| 3030 | cdef object _list_py_constants |
| 3031 | cdef int _n_py_constants |
| 3032 | cdef PyObject** _py_constants |
| 3033 | cdef int _n_stack |
| 3034 | cdef double* _stack |
| 3035 | cdef int _n_code |
| 3036 | cdef int* _code |
| 3037 | ... |
| 3038 | |
| 3039 | Contrast the declaration of ``_stack`` here with the |
| 3040 | ElementInterpreter version. To simplify our handling of |
| 3041 | reference counting and garbage collection, in a Python-object |
| 3042 | based interpreter, we allocate arrays as Python lists, |
| 3043 | and then pull the array out of the innards of the list. |
| 3044 | sage: print el_wrapper |
| 3045 | # ... |
| 3046 | cdef object _list_stack |
| 3047 | cdef int _n_stack |
| 3048 | cdef PyObject** _stack |
| 3049 | ... |
| 3050 | |
| 3051 | Next is the __init__ method, which starts like this: |
| 3052 | sage: print rdf_wrapper |
| 3053 | # ... |
| 3054 | def __init__(self, args): |
| 3055 | Wrapper.__init__(self, args, metadata) |
| 3056 | cdef int i |
| 3057 | cdef int count |
| 3058 | ... |
| 3059 | |
| 3060 | To make it possible to generate code for all expression |
| 3061 | interpreters with a single code generator, all wrappers |
| 3062 | have the same API. The __init__ method takes a single |
| 3063 | argument (here called *args*), which is a dictionary holding |
| 3064 | all the information needed to initialize this wrapper. |
| 3065 | |
| 3066 | We call Wrapper.__init__, which saves a copy of this arguments |
| 3067 | object and of the interpreter metadata in the wrapper. (This is |
| 3068 | only used for debugging.) |
| 3069 | |
| 3070 | Now we allocate memory for each memory chunk. (We allocate |
| 3071 | the memory here, and reuse it on each call of the |
| 3072 | wrapper/interpreter. This is for speed reasons; in a fast |
| 3073 | interpreter like RDFInterpreter, there are no memory allocations |
| 3074 | involved in a call of the wrapper, except for the ones that |
| 3075 | are required by the Python calling convention. Eventually |
| 3076 | we will support alternate Cython-only entry points that do |
| 3077 | absolutely no memory allocation.) |
| 3078 | |
| 3079 | Basically the same code is repeated, with minor variations, for |
| 3080 | each memory chunk; for brevity, we'll only show the code |
| 3081 | for 'constants'. |
| 3082 | |
| 3083 | sage: print rdf_wrapper |
| 3084 | # ... |
| 3085 | val = args['constants'] |
| 3086 | self._n_constants = len(val) |
| 3087 | self._constants = <double*>sage_malloc(sizeof(double) * len(val)) |
| 3088 | if self._constants == NULL: raise MemoryError |
| 3089 | for i in range(len(val)): |
| 3090 | self._constants[i] = val[i] |
| 3091 | ... |
| 3092 | |
| 3093 | Recall that _n_constants is an int, and _constants is a |
| 3094 | double*. |
| 3095 | |
| 3096 | The RRInterpreter version is more complicated, because it has to |
| 3097 | call mpfr_init. |
| 3098 | sage: print rr_wrapper |
| 3099 | # ... |
| 3100 | cdef RealNumber rn |
| 3101 | ... |
| 3102 | val = args['constants'] |
| 3103 | self._n_constants = len(val) |
| 3104 | self._constants = <mpfr_t*>sage_malloc(sizeof(mpfr_t) * len(val)) |
| 3105 | if self._constants == NULL: raise MemoryError |
| 3106 | for i in range(len(val)): |
| 3107 | mpfr_init2(self._constants[i], self.domain.prec()) |
| 3108 | for i in range(len(val)): |
| 3109 | rn = self.domain(val[i]) |
| 3110 | mpfr_set(self._constants[i], rn.value, GMP_RNDN) |
| 3111 | ... |
| 3112 | |
| 3113 | And as we mentioned above, in Python-object based interpreters |
| 3114 | we actually allocate the memory as a Python list. |
| 3115 | sage: print el_wrapper |
| 3116 | # ... |
| 3117 | val = args['constants'] |
| 3118 | self._n_constants = len(val) |
| 3119 | self._list_constants = PyList_New(self._n_constants) |
| 3120 | self._constants = (<PyListObject *>self._list_constants).ob_item |
| 3121 | for i in range(len(val)): |
| 3122 | self._constants[i] = <PyObject *>val[i]; Py_INCREF(self._constants[i]) |
| 3123 | ... |
| 3124 | |
| 3125 | Of course, once we've allocated the memory, we eventually have |
| 3126 | to free it. (Again, we'll only look at 'constants'.) |
| 3127 | sage: print rdf_wrapper |
| 3128 | # ... |
| 3129 | def __dealloc__(self): |
| 3130 | ... |
| 3131 | if self._constants: |
| 3132 | sage_free(self._constants) |
| 3133 | ... |
| 3134 | |
| 3135 | The RRInterpreter code is more complicated again because it has |
| 3136 | to call mpfr_clear. |
| 3137 | sage: print rr_wrapper |
| 3138 | # ... |
| 3139 | def __dealloc__(self): |
| 3140 | cdef int i |
| 3141 | ... |
| 3142 | if self._constants: |
| 3143 | for i in range(self._n_constants): |
| 3144 | mpfr_clear(self._constants[i]) |
| 3145 | sage_free(self._constants) |
| 3146 | ... |
| 3147 | |
| 3148 | But the ElementInterpreter code is extremely simple -- |
| 3149 | it doesn't have to do anything to deallocate constants! |
| 3150 | (Since the memory for constants is actually allocated as a |
| 3151 | Python list, and Cython knows how to deallocate Python lists.) |
| 3152 | |
| 3153 | Finally we get to the __call__ method. We grab the arguments |
| 3154 | passed by the caller, stuff them in our pre-allocated |
| 3155 | argument array, and then call the C interpreter. |
| 3156 | sage: print rdf_wrapper |
| 3157 | # ... |
| 3158 | def __call__(self, *args): |
| 3159 | if self._n_args != len(args): raise ValueError |
| 3160 | cdef double* c_args = self._args |
| 3161 | cdef int i |
| 3162 | for i from 0 <= i < len(args): |
| 3163 | self._args[i] = args[i] |
| 3164 | return interp_rdf(c_args |
| 3165 | , self._constants |
| 3166 | , self._py_constants |
| 3167 | , self._stack |
| 3168 | , self._code |
| 3169 | ) |
| 3170 | ... |
| 3171 | |
| 3172 | In Python-object based interpreters, the call to the C |
| 3173 | interpreter has to be a little more complicated. We don't |
| 3174 | want to hold on to Python objects from an old computation by |
| 3175 | leaving them referenced from the stack. In normal operation, |
| 3176 | the C interpreter clears out the stack as it runs, leaving the |
| 3177 | stack totally clear when the interpreter finishes. However, |
| 3178 | this doesn't happen if the C interpreter raises an exception. |
| 3179 | In that case, we have to clear out any remnants from the stack |
| 3180 | in the wrapper. |
| 3181 | sage: print el_wrapper |
| 3182 | # ... |
| 3183 | try: |
| 3184 | return interp_el((<PyListObject*>mapped_args).ob_item |
| 3185 | , self._constants |
| 3186 | , self._stack |
| 3187 | , <PyObject*>self._domain |
| 3188 | , self._code |
| 3189 | ) |
| 3190 | except: |
| 3191 | for i in range(self._n_stack): |
| 3192 | Py_CLEAR(self._stack[i]) |
| 3193 | raise |
| 3194 | ... |
| 3195 | |
| 3196 | That's it for the wrapper class. The only thing remaining is |
| 3197 | the interpreter metadata. This is the information necessary |
| 3198 | for the code generator to map instruction names to opcodes; it |
| 3199 | also gives information about stack usage, etc. This is fully |
| 3200 | documented at InterpreterMetadata; for now, we'll just show |
| 3201 | what it looks like. |
| 3202 | |
| 3203 | Currently, there are two parts to the metadata; the first maps |
| 3204 | instruction names to instruction descriptions. The second one |
| 3205 | maps opcodes to instruction descriptions. Note that we don't |
| 3206 | use InstrSpec objects here; instead, we use CompilerInstrSpec |
| 3207 | objects, which are much simpler and contain only the information |
| 3208 | we'll need at runtime. |
| 3209 | |
| 3210 | First the part that maps instruction names to |
| 3211 | (CompilerInstrSpec, opcode) pairs. |
| 3212 | |
| 3213 | sage: print rdf_wrapper |
| 3214 | # ... |
| 3215 | from sage.ext.fast_callable import CompilerInstrSpec, InterpreterMetadata |
| 3216 | metadata = InterpreterMetadata(by_opname={ |
| 3217 | ... |
| 3218 | 'return': |
| 3219 | (CompilerInstrSpec(1, 0, []), 2), |
| 3220 | 'py_call': |
| 3221 | (CompilerInstrSpec(0, 1, ['py_constants', 'n_inputs']), 3), |
| 3222 | 'add': |
| 3223 | (CompilerInstrSpec(2, 1, []), 4), |
| 3224 | ... |
| 3225 | }, ...) |
| 3226 | |
| 3227 | There's also a table that maps opcodes to (instruction name, |
| 3228 | CompilerInstrSpec) pairs: |
| 3229 | sage: print rdf_wrapper |
| 3230 | # ... |
| 3231 | metadata = InterpreterMetadata(..., by_opcode=[ |
| 3232 | ... |
| 3233 | ('return', |
| 3234 | CompilerInstrSpec(1, 0, [])), |
| 3235 | ('py_call', |
| 3236 | CompilerInstrSpec(0, 1, ['py_constants', 'n_inputs'])), |
| 3237 | ('add', |
| 3238 | CompilerInstrSpec(2, 1, [])), |
| 3239 | ... |
| 3240 | ]) |
| 3241 | |
| 3242 | And that's it for the wrapper. |
| 3243 | """ |
| 3244 | import cStringIO |
| 3245 | buff = cStringIO.StringIO() |
| 3246 | self.write_wrapper(buff.write) |
| 3247 | return buff.getvalue() |
| 3248 | |
| 3249 | def write_if_changed(fn, value): |
| 3250 | r""" |
| 3251 | Writes value to the file named fn, if value is different than |
| 3252 | the current contents. |
| 3253 | |
| 3254 | EXAMPLES: |
| 3255 | sage: from sage.ext.gen_interpreters import * |
| 3256 | sage: def last_modification(fn): return os.stat(fn).st_mtime |
| 3257 | sage: fn = tmp_filename('gen_interp') |
| 3258 | sage: write_if_changed(fn, 'Hello, world') |
| 3259 | sage: t1 = last_modification(fn) |
| 3260 | sage: open(fn).read() |
| 3261 | 'Hello, world' |
| 3262 | sage: sleep(2) # long time |
| 3263 | sage: write_if_changed(fn, 'Goodbye, world') |
| 3264 | sage: t2 = last_modification(fn) |
| 3265 | sage: open(fn).read() |
| 3266 | 'Goodbye, world' |
| 3267 | sage: sleep(2) # long time |
| 3268 | sage: write_if_changed(fn, 'Goodbye, world') |
| 3269 | sage: t3 = last_modification(fn) |
| 3270 | sage: open(fn).read() |
| 3271 | 'Goodbye, world' |
| 3272 | sage: t1 == t2 # long time |
| 3273 | False |
| 3274 | sage: t2 == t3 |
| 3275 | True |
| 3276 | """ |
| 3277 | old_value = None |
| 3278 | try: |
| 3279 | with open(fn) as file: |
| 3280 | old_value = file.read() |
| 3281 | except IOError: |
| 3282 | pass |
| 3283 | |
| 3284 | if value != old_value: |
| 3285 | # We try to remove the file, in case it exists. This is to |
| 3286 | # automatically break hardlinks... see #5350 for motivation. |
| 3287 | try: |
| 3288 | os.remove(fn) |
| 3289 | except OSError: |
| 3290 | pass |
| 3291 | |
| 3292 | with open(fn, 'w') as file: |
| 3293 | file.write(value) |
| 3294 | |
| 3295 | def build_interp(interp_spec, dir): |
| 3296 | r""" |
| 3297 | Given an InterpreterSpec, writes the C interpreter and the Cython |
| 3298 | wrapper. |
| 3299 | |
| 3300 | EXAMPLES: |
| 3301 | sage: from sage.ext.gen_interpreters import * |
| 3302 | sage: testdir = tmp_filename() |
| 3303 | sage: os.mkdir(testdir) |
| 3304 | sage: rdf_interp = RDFInterpreter() |
| 3305 | sage: build_interp(rdf_interp, testdir) |
| 3306 | sage: open(testdir + '/interp_rdf.c').readline() |
| 3307 | '/* Automatically generated. Do not edit! */\n' |
| 3308 | """ |
| 3309 | ig = InterpreterGenerator(interp_spec) |
| 3310 | interp_fn = '%s/interp_%s.c' % (dir, interp_spec.name) |
| 3311 | wrapper_fn = '%s/wrapper_%s.pyx' % (dir, interp_spec.name) |
| 3312 | interp = ig.get_interpreter() |
| 3313 | wrapper = ig.get_wrapper() |
| 3314 | write_if_changed(interp_fn, interp) |
| 3315 | write_if_changed(wrapper_fn, wrapper) |
| 3316 | |
| 3317 | def rebuild(dir): |
| 3318 | r""" |
| 3319 | Check whether the interpreter and wrapper sources have been written |
| 3320 | since the last time this module was changed. If not, write them. |
| 3321 | |
| 3322 | EXAMPLES: |
| 3323 | sage: from sage.ext.gen_interpreters import * |
| 3324 | sage: testdir = tmp_filename() |
| 3325 | sage: os.mkdir(testdir) |
| 3326 | sage: rebuild(testdir) |
| 3327 | Building interpreters for fast_callable |
| 3328 | sage: rebuild(testdir) |
| 3329 | sage: open(testdir + '/wrapper_el.pyx').readline() |
| 3330 | '# Automatically generated. Do not edit!\n' |
| 3331 | """ |
| 3332 | module_mtime = os.stat(__file__).st_mtime |
| 3333 | try: |
| 3334 | if os.stat(dir + '/timestamp').st_mtime > module_mtime: |
| 3335 | # No need to rebuild. |
| 3336 | return |
| 3337 | except OSError: |
| 3338 | pass |
| 3339 | |
| 3340 | # This line will show up "sage -b" (once per upgrade, not every time |
| 3341 | # you run it). |
| 3342 | print "Building interpreters for fast_callable" |
| 3343 | |
| 3344 | interp = RDFInterpreter() |
| 3345 | build_interp(interp, dir) |
| 3346 | |
| 3347 | interp = RRInterpreter() |
| 3348 | build_interp(interp, dir) |
| 3349 | |
| 3350 | interp = PythonInterpreter() |
| 3351 | build_interp(interp, dir) |
| 3352 | |
| 3353 | interp = ElementInterpreter() |
| 3354 | build_interp(interp, dir) |
| 3355 | |
| 3356 | # Do this last, so we don't do it if there's an error above. |
| 3357 | with open(dir + '/timestamp', 'w'): |
| 3358 | pass |
| 3359 | |
| 3360 | # This list of modules gets added to the list in module_list.py. |
| 3361 | # For now, that's not important -- we could have just put this |
| 3362 | # list in module_list.py directly. But eventually, we'll have |
| 3363 | # interpreters that are conditionally built (for example, |
| 3364 | # interpreters that rely on SSE so they only work on x86), so |
| 3365 | # it makes sense to keep the decisions about which interpreters |
| 3366 | # to write and which interpreters to build in the same place. |
| 3367 | modules = [ |
| 3368 | Extension('sage.ext.interpreters.wrapper_rdf', |
| 3369 | sources = ['sage/ext/interpreters/wrapper_rdf.pyx', |
| 3370 | 'sage/ext/interpreters/interp_rdf.c']), |
| 3371 | |
| 3372 | Extension('sage.ext.interpreters.wrapper_rr', |
| 3373 | sources = ['sage/ext/interpreters/wrapper_rr.pyx', |
| 3374 | 'sage/ext/interpreters/interp_rr.c'], |
| 3375 | libraries=['mpfr']), |
| 3376 | |
| 3377 | Extension('sage.ext.interpreters.wrapper_py', |
| 3378 | sources = ['sage/ext/interpreters/wrapper_py.pyx', |
| 3379 | 'sage/ext/interpreters/interp_py.c']), |
| 3380 | |
| 3381 | Extension('sage.ext.interpreters.wrapper_el', |
| 3382 | sources = ['sage/ext/interpreters/wrapper_el.pyx', |
| 3383 | 'sage/ext/interpreters/interp_el.c']), |
| 3384 | |
| 3385 | ] |