Path: blob/develop/src/sage_setup/autogen/interpreters/internal/specs/python.py
4089 views
# ****************************************************************************1# Copyright (C) 2009 Carl Witty <[email protected]>2# Copyright (C) 2015 Jeroen Demeyer <[email protected]>3#4# This program is free software: you can redistribute it and/or modify5# it under the terms of the GNU General Public License as published by6# the Free Software Foundation, either version 2 of the License, or7# (at your option) any later version.8# https://www.gnu.org/licenses/9# ****************************************************************************10from .base import StackInterpreter11from ..instructions import (params_gen, instr_funcall_2args, instr_unary,12InstrSpec)13from ..memory import MemoryChunk14from ..storage import ty_python15from ..utils import je, reindent_lines as ri161718class MemoryChunkPythonArguments(MemoryChunk):19r"""20A special-purpose memory chunk, for the generic Python-object based21interpreter. Rather than copy the arguments into an array allocated22in the wrapper, we use the PyTupleObject internals and pass the array23that's inside the argument tuple.24"""2526def declare_class_members(self):27r"""28Return a string giving the declarations of the class members29in a wrapper class for this memory chunk.3031EXAMPLES::3233sage: from sage_setup.autogen.interpreters.internal import *34sage: from sage_setup.autogen.interpreters.internal.specs.python import *35sage: mc = MemoryChunkPythonArguments('args', ty_python)36"""37return " cdef int _n_%s\n" % self.name3839def init_class_members(self):40r"""41Return a string to be put in the __init__ method of a wrapper42class using this memory chunk, to initialize the corresponding43class members.4445EXAMPLES::4647sage: from sage_setup.autogen.interpreters.internal import *48sage: from sage_setup.autogen.interpreters.internal.specs.python import *49sage: mc = MemoryChunkPythonArguments('args', ty_python)50sage: mc.init_class_members()51" count = args['args']\n self._n_args = count\n"52"""53return je(ri(8,54"""55count = args['{{ myself.name }}']56self._n_args = count57"""), myself=self)5859def setup_args(self):60r"""61Handle the arguments of __call__. Nothing to do.6263EXAMPLES::6465sage: from sage_setup.autogen.interpreters.internal import *66sage: from sage_setup.autogen.interpreters.internal.specs.python import *67sage: mc = MemoryChunkPythonArguments('args', ty_python)68sage: mc.setup_args()69''70"""71return ''7273def pass_argument(self):74r"""75Pass the innards of the argument tuple to the interpreter.7677EXAMPLES::7879sage: from sage_setup.autogen.interpreters.internal import *80sage: from sage_setup.autogen.interpreters.internal.specs.python import *81sage: mc = MemoryChunkPythonArguments('args', ty_python)82sage: mc.pass_argument()83'(<PyTupleObject*>args).ob_item'84"""85return "(<PyTupleObject*>args).ob_item"868788class MemoryChunkPyConstant(MemoryChunk):89r"""90A special-purpose memory chunk, for holding a single Python constant91and passing it to the interpreter as a PyObject*.92"""9394def __init__(self, name):95r"""96Initialize an instance of MemoryChunkPyConstant.9798Always uses the type ty_python.99100EXAMPLES::101102sage: from sage_setup.autogen.interpreters.internal import *103sage: from sage_setup.autogen.interpreters.internal.specs.python import *104sage: mc = MemoryChunkPyConstant('domain')105sage: mc.name106'domain'107sage: mc.storage_type is ty_python108True109"""110super(MemoryChunkPyConstant, self).__init__(name, ty_python)111112def declare_class_members(self):113r"""114Return a string giving the declarations of the class members115in a wrapper class for this memory chunk.116117EXAMPLES::118119sage: from sage_setup.autogen.interpreters.internal import *120sage: from sage_setup.autogen.interpreters.internal.specs.python import *121sage: mc = MemoryChunkPyConstant('domain')122sage: mc.declare_class_members()123' cdef object _domain\n'124"""125return je(ri(4,126"""127cdef object _{{ myself.name }}128"""), myself=self)129130def init_class_members(self):131r"""132Return a string to be put in the __init__ method of a wrapper133class using this memory chunk, to initialize the corresponding134class members.135136EXAMPLES::137138sage: from sage_setup.autogen.interpreters.internal import *139sage: from sage_setup.autogen.interpreters.internal.specs.python import *140sage: mc = MemoryChunkPyConstant('domain')141sage: mc.init_class_members()142" self._domain = args['domain']\n"143"""144return je(ri(8,145"""146self._{{ myself.name }} = args['{{ myself.name }}']147"""), myself=self)148149def declare_parameter(self):150r"""151Return the string to use to declare the interpreter parameter152corresponding to this memory chunk.153154EXAMPLES::155156sage: from sage_setup.autogen.interpreters.internal import *157sage: from sage_setup.autogen.interpreters.internal.specs.python import *158sage: mc = MemoryChunkPyConstant('domain')159sage: mc.declare_parameter()160'PyObject* domain'161"""162return 'PyObject* %s' % self.name163164def pass_argument(self):165r"""166Return the string to pass the argument corresponding to this167memory chunk to the interpreter.168169EXAMPLES::170171sage: from sage_setup.autogen.interpreters.internal import *172sage: from sage_setup.autogen.interpreters.internal.specs.python import *173sage: mc = MemoryChunkPyConstant('domain')174sage: mc.pass_argument()175'<PyObject*>self._domain'176"""177return '<PyObject*>self._%s' % self.name178179180class PythonInterpreter(StackInterpreter):181r"""182A subclass of StackInterpreter, specifying an interpreter over183Python objects.184185Let's discuss how the reference-counting works in Python-object186based interpreters.187188There is a simple rule to remember: when executing the code189snippets, the input variables contain borrowed references;190you must fill in the output variables with references you own.191192As an optimization, an instruction may set .handles_own_decref; in193that case, it must decref any input variables that came from the194stack. (Input variables that came from arguments/constants chunks195must NOT be decref'ed!) In addition, with .handles_own_decref, if196any of your input variables are arbitrary-count, then you must197NULL out these variables as you decref them. (Use Py_CLEAR to do198this, unless you understand the documentation of Py_CLEAR and why199it's different than Py_XDECREF followed by assigning NULL.)200201Note that as a tiny optimization, the interpreter always assumes202(and ensures) that empty parts of the stack contain NULL, so203it doesn't bother to Py_XDECREF before it pushes onto the stack.204"""205206name = 'py'207208def __init__(self):209r"""210Initialize a PythonInterpreter.211212EXAMPLES::213214sage: from sage_setup.autogen.interpreters.internal import *215sage: from sage_setup.autogen.interpreters.internal.specs.python import *216sage: interp = PythonInterpreter()217sage: interp.name218'py'219sage: interp.mc_args220{MC:args}221sage: interp.chunks222[{MC:args}, {MC:constants}, {MC:stack}, {MC:code}]223sage: instrs = dict([(ins.name, ins) for ins in interp.instr_descs])224sage: instrs['add']225add: SS->S = 'o0 = PyNumber_Add(i0, i1);'226sage: instrs['py_call']227py_call: *->S = '\nPyObject *py_args...CREF(py_args);\n'228"""229230super(PythonInterpreter, self).__init__(ty_python)231# StackInterpreter.__init__ gave us a MemoryChunkArguments.232# Override with MemoryChunkPythonArguments.233self.mc_args = MemoryChunkPythonArguments('args', ty_python)234self.chunks = [self.mc_args, self.mc_constants, self.mc_stack,235self.mc_code]236self.c_header = ri(0,237"""238#define CHECK(x) (x != NULL)239""")240241self.pyx_header = ri(0,242"""\243from cpython.number cimport PyNumber_TrueDivide244""")245246pg = params_gen(A=self.mc_args, C=self.mc_constants, D=self.mc_code,247S=self.mc_stack)248self.pg = pg249250instrs = [251InstrSpec('load_arg', pg('A[D]', 'S'),252code='o0 = i0; Py_INCREF(o0);'),253InstrSpec('load_const', pg('C[D]', 'S'),254code='o0 = i0; Py_INCREF(o0);'),255InstrSpec('return', pg('S', ''),256code='return i0;',257handles_own_decref=True),258InstrSpec('py_call', pg('C[D]S@D', 'S'),259handles_own_decref=True,260code=ri(0, """261PyObject *py_args = PyTuple_New(n_i1);262if (py_args == NULL) goto error;263int i;264for (i = 0; i < n_i1; i++) {265PyObject *arg = i1[i];266PyTuple_SET_ITEM(py_args, i, arg);267i1[i] = NULL;268}269o0 = PyObject_CallObject(i0, py_args);270Py_DECREF(py_args);271"""))272]273274binops = [275('add', 'PyNumber_Add'),276('sub', 'PyNumber_Subtract'),277('mul', 'PyNumber_Multiply'),278('div', 'PyNumber_TrueDivide'),279('floordiv', 'PyNumber_FloorDivide')280]281282for (name, op) in binops:283instrs.append(instr_funcall_2args(name, pg('SS', 'S'), op))284instrs.append(InstrSpec('pow', pg('SS', 'S'),285code='o0 = PyNumber_Power(i0, i1, Py_None);'))286instrs.append(InstrSpec('ipow', pg('SC[D]', 'S'),287code='o0 = PyNumber_Power(i0, i1, Py_None);'))288for (name, op) in [('neg', 'PyNumber_Negative'),289('invert', 'PyNumber_Invert'),290('abs', 'PyNumber_Absolute')]:291instrs.append(instr_unary(name, pg('S', 'S'), '%s(i0)' % op))292self.instr_descs = instrs293self._set_opcodes()294# Always use ipow295self.ipow_range = True296# We don't yet support call_c for Python-object interpreters297# (the default implementation doesn't work, because of298# object vs. PyObject* confusion)299self.implement_call_c = False300301302