|
1 | 1 | # Implementation Details |
2 | 2 |
|
3 | | -## Abstract Operations on Python Objects |
4 | | - |
5 | | -Many generic operations on Python objects in CPython are defined in the header |
6 | | -files `object.h` and `abstract.h`. These operations are widely used and their |
7 | | -interplay and intricacies are the cause for the conversion, error message, and |
8 | | -control flow bugs when not mimicked correctly. Our current approach is to |
9 | | -provide many of these abstract operations as part of the `PythonObjectLibrary`. |
10 | | - |
11 | | -### Common operations in the PythonObjectLibrary |
12 | | - |
13 | | -The code has evolved over time, so not all built-in nodes are prime examples of |
14 | | -messages that should be used from the PythonObjectLibrary. We are refactoring |
15 | | -this as we go, but here are a few examples for things you can (or should soon be |
16 | | -able to) use the PythonObjectLibrary for: |
17 | | - |
18 | | - - casting and coercion to `java.lang.String`, array-sized Java `int`, Python |
19 | | - index, fileno, `double`, filesystem path, iterator, and more |
20 | | - - reading the class of an object |
21 | | - - accessing the `__dict__` attribute of an object |
22 | | - - hashing objects and testing for equality |
23 | | - - testing for truthy-ness |
24 | | - - getting the length |
25 | | - - testing for abstract types such as `mapping`, `sequence`, `callable` |
26 | | - - invoking methods or executing callables |
27 | | - - access objects through the buffer protocol |
28 | | - |
29 | | -### PythonObjectLibrary functions with and without state |
30 | | - |
31 | | -Usually, there are at least two messages for each operation - one that takes a |
32 | | -`ThreadState` argument, and one that doesn't. The intent is to allow passing of |
33 | | -exception state and caller information similar to how we do it with the `PFrame` |
34 | | -argument even across library messages, which cannot take a VirtualFrame. |
35 | | - |
36 | | -All nodes that are used in message implementations must allow uncached |
37 | | -usage. Often (e.g. in the case of the generic `CallNode`) they offer execute |
38 | | -methods with and without frames. If a `ThreadState` was passed to the message, a |
39 | | -frame to pass to the node can be reconstructed using |
40 | | -`PArguments.frameForCall(threadState)`. Here's an example: |
41 | | - |
42 | | -```java |
43 | | -@ExportMessage |
44 | | -long messageWithState(ThreadState state, |
45 | | - @Cached CallNode callNode) { |
46 | | - Object callable = ... |
47 | | - |
48 | | - if (state != null) { |
49 | | - return callNode.execute(PArguments.frameForCall(state), callable, arguments); |
50 | | - } else { |
51 | | - return callNode.execute(callable, arguments); |
52 | | - } |
53 | | -} |
54 | | -``` |
55 | | - |
56 | | -*Note*: It is **always** preferable to call an `execute` method with a |
57 | | -`VirtualFrame` when both one with and without exist! The reason is that this |
58 | | -avoids materialization of the frame state in more cases, as described on the |
59 | | -section on Python's global thread state above. |
60 | | - |
61 | | -### Other libraries in the codebase |
62 | | - |
63 | | -Accessing hashing storages (the storage for `dict`, `set`, and `frozenset`) |
64 | | -should be done via the `HashingStorageLibrary`. We are in the process of |
65 | | -creating a `SequenceStorageLibrary` for sequence types (`tuple`, `list`) to |
66 | | -replace the `SequenceStorageNodes` collection of classes. |
67 | | - |
68 | 3 | ## Python Global Thread State |
69 | 4 |
|
70 | 5 | In CPython, each stack frame is allocated on the heap, and there's a global |
|
0 commit comments