Skip to content

Means to expose built-in types to Python#205

Merged
jeff5 merged 6 commits into
jython:mainfrom
jeff5:expose-bi-3.8
Sep 15, 2022
Merged

Means to expose built-in types to Python#205
jeff5 merged 6 commits into
jython:mainfrom
jeff5:expose-bi-3.8

Conversation

@jeff5

@jeff5 jeff5 commented Aug 20, 2022

Copy link
Copy Markdown
Member

This is going to be quite a big PR.

So far, we can expose the special methods of built-in types through slots, so that they may be called by the interpreter. They are recognised by their special name and signature when building a type.

In order to give built-in types their methods, we have to support names and signatures that are arbitrary (within the rules of Python). In Jython 2 we have an exposure mechanism that creates a class for each method in which __call__ is given a body that calls the specific method wrapped, with generated argument coercion (I think). This was the only available approach before the MethodHandle was added to Java for the benefit of dynamic language implementers. (That's us!)

The mechanism for this (the Jython 2 exposer) is not well documented and produces code that cannot be debugged (in my experience). I do not know how I would adapt it to create MethodHandles. So the Very Slow Jython Project took a different direction, which:

  • leads to a MethodHandle one could use in a dynamic call site,
  • goes directly to the Java method implementation in simple cases,
  • offers the full range of Python signatures.

This PR ports a big chunk of that to the main Jython repo. We cannot evidence a claim that this mechanism is faster than calls in Jython 2. (I'm quietly confident it won't be slower.)

This PR will introduce the necessary moving parts by tested stages. The first part of the mechanism is a parser for arguments in the form they appear on the interpreter stack, or could be presented from the Java stack. In practice we'll look for short-cuts in common cases (small number of arguments by position) but the general mechanism has to be there first. It is also good for filling the frame of a method defined in Python. The use of a single mechanism means that the full range of Python signatures is available to built-in types and modules.

We introduce a class (and its test) that will take argument lists as
they might be provided to methods and functions, and arranges them in an
array. Variants are given intended to cover any Python 3 calling
pattern.
@jeff5 jeff5 marked this pull request as draft August 20, 2022 16:48
We add the apparatus to describe methods by their Python arguments. This
is the intermediate representation on the way to exposing each as an
object. We test this intermediate structure holds a good ArgParser.

Note that we must ask the compiler to preserve argument names for run
time to get a Python-like signature.
@jeff5

jeff5 commented Aug 21, 2022

Copy link
Copy Markdown
Member Author

The next installment of the story involves enumerating the methods of a type we wish to expose. We build an argument parser for each. For this purpose, we supply a set of annotations to pick out the methods in question and make choices that Java does not offer us, such as where the keyword-only parameters begin. We process these to create a specification (CallableSpec) of which the ArgParser forms the major part.

At this stage we do not yet have anything we can call. We just check we get the right ArgParser.

jeff5 added 2 commits August 21, 2022 19:20
We add method signatures that include argument collectors (varargs and
varkeywords) and switch to using parameterised tests to make selective
debugging easier.
We introduce types that represent the methods of built-in types, and
their bound counterparts, and which can be created from the type
exposer.

We demonstrate in a test that we can call the target method through the
__call__ method on both the unbound descriptor and the bound method.
@jeff5

jeff5 commented Aug 22, 2022

Copy link
Copy Markdown
Member Author

This installment defines the public-facing classes for method descriptors and functions (or bound methods). We show that we can call them from Java by their classic __call__ method and a Java-friendly call with non-array arguments on the JVM stack.

We cannot yet call from Python byte code.

jeff5 added 2 commits August 25, 2022 09:21
We change PyCode and PyFrame so that identifiers (names, keywords)
appearing in code are represented as interned Java String, since we
expect this to be more efficient in look-up and comparison.

The marshal module gives this interpretation to the 't' type, which
CPython uses for identifiers.
We decorate a small number of methods in PyUnicode with the annotations
from Exposed.java, to define their Python calling semantics (positional
parameters, defaults, keywords). We implement the several CALL_* byte
codes and demonstrate them in a test.
@jeff5

jeff5 commented Aug 26, 2022

Copy link
Copy Markdown
Member Author

We can now expose methods of built-in ("crafted") Python types where the methods have been annotated. We have (I think) the full expressive power of Python method signatures.

Initially I thought I would include exposure of members and get-set attributes, but this is huge already, so that's another PR.

We need this, the follow-up members and get-sets, and probably module exposure, to support the AST work, so I propose waiting a week (probably while I release a 2.7.3rc1) then I'll present the next stage as a new PR.

@jeff5 jeff5 marked this pull request as ready for review August 26, 2022 07:00
@jeff5

jeff5 commented Aug 28, 2022

Copy link
Copy Markdown
Member Author

@fwierzbicki : pinging you here more for your interest than to invite a line-by-line review.

I think this, and more pertinently a follow-up to support members and attributes, is on the path to being able to generate an AST, since AST nodes surely have exposed methods and attributes.

Modules use the same annotations, but I'm struggling a bit with the exposer for those.

@jeff5 jeff5 merged commit 6d9882d into jython:main Sep 15, 2022
@jeff5 jeff5 deleted the expose-bi-3.8 branch September 15, 2022 07:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant