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)
|