File: interp_hpy.py

package info (click to toggle)
pypy3 7.3.11%2Bdfsg-2%2Bdeb12u3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 201,024 kB
  • sloc: python: 1,950,308; ansic: 517,580; sh: 21,417; asm: 14,419; cpp: 4,263; makefile: 4,228; objc: 761; xml: 530; exp: 499; javascript: 314; pascal: 244; lisp: 45; csh: 11; awk: 4
file content (167 lines) | stat: -rw-r--r-- 6,200 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
from rpython.rtyper.lltypesystem import lltype, rffi
from rpython.rlib.rdynload import dlopen, dlsym, DLOpenError
from rpython.rlib.objectmodel import specialize

from pypy.interpreter.gateway import unwrap_spec, interp2app
from pypy.interpreter.error import raise_import_error
from pypy.interpreter.error import oefmt

from pypy.module._hpy_universal import llapi
from pypy.module._hpy_universal.state import State
from pypy.module._hpy_universal.apiset import API
from pypy.module._hpy_universal.llapi import BASE_DIR

# these imports have side effects, as they call @API.func()
from pypy.module._hpy_universal import (
    interp_err,
    interp_long,
    interp_module,
    interp_number,
    interp_unicode,
    interp_float,
    interp_bytes,
    interp_call,
    interp_dict,
    interp_list,
    interp_tuple,
    interp_builder,
    interp_object,
    interp_cpy_compat,
    interp_type,
    interp_tracker,
    interp_import,
    interp_field,
    interp_state,
    )

# ~~~ Some info on the debug mode ~~~
#
# The following is an explation of what happens when you load a module in
# debug mode and how it works:
#
# 1. someone calls _hpy_universal.load(..., debug=True), which calls
#    init_hpy_module
#
# 2. init_hpy_module(debug=True) calls HPyInit_foo(dctx)
#
# 3. HPyInit_foo calls HPyModule_Create(), which calls dctx->ctx_Module_Create.
#    This function is a wrapper around interp_module.debug_HPyModule_Create(),
#    created by the @DEBUG.func() decorator.
#
# 4. The wrapper calls:
#       handles = State.get(space).get_handle_manager(self.is_debug)
#    and passes it to debug_HPyModule_Create()
#    This means that depending on the value of debug, we get either
#    HandleManager or DebugHandleManager. This handle manager is passed to
#    _hpymodule_create() which ends up creating instances of
#    handles.w_ExtensionFunction (i.e. of W_ExtensionFunction_d)
#
# 5. When we call a function or a method, we ultimately end up in
#    W_ExtensionFunction_{u,d}.call_{noargs,o,...}, which uses self.handles: so, the
#    net result is that depending on the value of debug at point (1), we call
#    the underlying C function with either dctx or uctx.
#
# 6. Argument passing works in the same way: handles are created by calling
#    self.handles.new, which in debug mode calls
#    llapi.hpy_debug_open_handle. The same for the return value, which calls
#    self.handles.consume which calls llapi.hpy_debug_close_handle.
#
# 7. We need to ensure that ALL python-to-C entry points use the correct
#    HandleManager/ctx: so the same applies for W_ExtensionMethod and
#    W_SlotWrapper.


def set_on_invalid_handle(space, w_f):
    raise oefmt(space.w_RuntimeError, "cannot use on_invalid_handle hook in PyPy")

@specialize.memo()
def get_set_on_invalid_handle(space):
    return interp2app(set_on_invalid_handle).spacebind(space)

def startup(space, w_mod):
    """
    Initialize _hpy_universal. This is called by moduledef.Module.__init__
    """
    from pypy.module._hpy_universal.interp_type import setup_hpy_storage
    state = State.get(space)
    state.setup(space)
    setup_hpy_storage()
    if not hasattr(space, 'is_fake_objspace'):
        # the following lines break test_ztranslation :(
        handles = state.get_handle_manager(debug=False)
        h_debug_mod = llapi.HPyInit__debug(handles.ctx)
        w_debug_mod = handles.consume(h_debug_mod)
        w_set_on_invalid_handle = get_set_on_invalid_handle(space)
        w_debug_mod.setdictvalue(space, 'set_on_invalid_handle', w_set_on_invalid_handle)
        w_mod.setdictvalue(space, '_debug', w_debug_mod)

def load_version():
    # eval the content of _vendored/hpy/devel/version.py without importing it
    version_py = BASE_DIR.join('version.py').read()
    d = {}
    exec(version_py, d)
    return d['__version__'], d['__git_revision__']
HPY_VERSION, HPY_GIT_REV = load_version()


@specialize.arg(4)
def init_hpy_module(space, name, origin, lib, debug, initfunc_ptr):
    state = space.fromcache(State)
    handles = state.get_handle_manager(debug)
    initfunc_ptr = rffi.cast(llapi.HPyInitFunc, initfunc_ptr)
    h_module = initfunc_ptr(handles.ctx)
    error = state.clear_exception()
    if error:
        raise error
    if not h_module:
        raise oefmt(space.w_SystemError,
            "initialization of %s failed without raising an exception",
            name)
    return handles.consume(h_module)

def descr_load_from_spec(space, w_spec):
    name = space.text_w(space.getattr(w_spec, space.newtext("name")))
    origin = space.fsencode_w(space.getattr(w_spec, space.newtext("origin")))
    return descr_load(space, name, origin)

@unwrap_spec(name='text', path='fsencode', debug=bool)
def descr_load(space, name, path, debug=False):
    try:
        with rffi.scoped_str2charp(path) as ll_libname:
            lib = dlopen(ll_libname, space.sys.dlopenflags)
    except DLOpenError as e:
        w_path = space.newfilename(path)
        raise raise_import_error(space,
            space.newfilename(e.msg), space.newtext(name), w_path)

    basename = name.split('.')[-1]
    init_name = 'HPyInit_' + basename
    try:
        initptr = dlsym(lib, init_name)
    except KeyError:
        msg = b"function %s not found in library %s" % (
            init_name, space.utf8_w(space.newfilename(path)))
        w_path = space.newfilename(path)
        raise raise_import_error(
            space, space.newtext(msg), space.newtext(name), w_path)
    if space.config.objspace.hpy_cpyext_API:
        # Ensure cpyext is initialised, since the extension might call cpyext
        # functions
        space.getbuiltinmodule('cpyext')
    if debug:
        return init_hpy_module(space, name, path, lib, True, initptr)
    else:
        return init_hpy_module(space, name, path, lib, False, initptr)

def descr_get_version(space):
    w_ver = space.newtext(HPY_VERSION)
    w_git_rev = space.newtext(HPY_GIT_REV)
    return space.newtuple([w_ver, w_git_rev])

@API.func("HPy HPy_Dup(HPyContext *ctx, HPy h)")
def HPy_Dup(space, handles, ctx, h):
    return handles.dup(h)

@API.func("void HPy_Close(HPyContext *ctx, HPy h)")
def HPy_Close(space, handles, ctx, h):
    handles.close(h)