Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Include/internal/pycore_optimizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,15 @@ typedef struct _JitOptContext {
// Arena for the symbolic types.
ty_arena t_arena;

// Arena for the descriptor mappings.
descr_arena d_arena;

JitOptRef *n_consumed;
JitOptRef *limit;
JitOptRef locals_and_stack[MAX_ABSTRACT_INTERP_SIZE];
_PyJitUopBuffer out_buffer;
// Index of the last escaped uop in out_buffer.
int last_escape_index;
} JitOptContext;


Expand Down Expand Up @@ -295,6 +300,9 @@ extern JitOptRef _Py_uop_sym_new_truthiness(JitOptContext *ctx, JitOptRef value,
extern bool _Py_uop_sym_is_compact_int(JitOptRef sym);
extern JitOptRef _Py_uop_sym_new_compact_int(JitOptContext *ctx);
extern void _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef sym);
extern JitOptRef _Py_uop_sym_new_descr_object(JitOptContext *ctx, unsigned int type_version);
extern JitOptRef _Py_uop_sym_get_attr(JitOptContext *ctx, JitOptRef ref, uint16_t slot_index);
extern JitOptRef _Py_uop_sym_set_attr(JitOptContext *ctx, JitOptRef ref, uint16_t slot_index, JitOptRef value);
extern JitOptRef _Py_uop_sym_new_predicate(JitOptContext *ctx, JitOptRef lhs_ref, JitOptRef rhs_ref, JitOptPredicateKind kind);
extern void _Py_uop_sym_apply_predicate_narrowing(JitOptContext *ctx, JitOptRef sym, bool branch_is_true);

Expand Down
36 changes: 36 additions & 0 deletions Include/internal/pycore_optimizer_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ extern "C" {

#define TY_ARENA_SIZE (UOP_MAX_TRACE_LENGTH * 5)

// Maximum descriptor mappings per object tracked symbolically
#define MAX_SYMBOLIC_DESCR_SIZE 16
#define DESCR_ARENA_SIZE (MAX_SYMBOLIC_DESCR_SIZE * 100)

// Need extras for root frame and for overflow frame (see TRACE_STACK_PUSH())
#define MAX_ABSTRACT_FRAME_DEPTH (16)

Expand All @@ -41,6 +45,7 @@ typedef enum _JitSymType {
JIT_SYM_TRUTHINESS_TAG = 9,
JIT_SYM_COMPACT_INT = 10,
JIT_SYM_PREDICATE_TAG = 11,
JIT_SYM_DESCR_TAG = 12,
} JitSymType;

typedef struct _jit_opt_known_class {
Expand Down Expand Up @@ -91,6 +96,31 @@ typedef struct {
uint8_t tag;
} JitOptCompactInt;

/*
Mapping from slot index or attribute offset to its symbolic value.
SAFETY:
This structure is used for both STORE_ATTR_SLOT and STORE_ATTR_INSTANCE_VALUE.
These two never appear on the same object type because:
__slots__ classes don't have Py_TPFLAGS_INLINE_VALUES
Therefore, there is no index collision between slot offsets and inline value offsets.
Note:
STORE_ATTR_WITH_HINT is NOT currently tracked.
If we want to track it in the future, we need to be careful about
potential index collisions with STORE_ATTR_INSTANCE_VALUE.
*/
typedef struct {
uint16_t slot_index;
uint16_t symbol;
} JitOptDescrMapping;
Comment on lines +111 to +114
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it safe to use this for both normal objects and objects with __slots__, or do we need a separate symbol?

Basically I'm asking if it's possible for an object to both have STORE_ATTR_INSTANCE_VALUE and STORE_ATTR_SLOT, as this will cause a index collision between the slots and offset. It it safe also with STORE_ATTR_WITH_HINT, as can that can mix with STORE_ATTR_INSTANCE_VALUE?

If you think of an answer, please let me know, and we can add it as a comment in the code. otherwise, this is kind of scary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two never appear on the same object type because:
STORE_ATTR_INSTANCE_VALUE needs Py_TPFLAGS_MANAGED_DICT flag.
Therefore, there is no index collision between slot offsets and inline value offsets.

cpython/Python/specialize.c

Lines 665 to 669 in 5f57f69

// No descriptor, or non overriding.
if ((type->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_NOT_MANAGED_DICT);
return 0;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, conflicts between STORE_ATTR_INSTANCE_VALUE and STORE_ATTR_WITH_HINT can indeed occur. Perhaps a flag could be added to the index to distinguish between the two types?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we track STORE_ATTR_WITH_HINT in this PR?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No lets ignore with hint for now.


typedef struct _jit_opt_descr {
uint8_t tag;
uint8_t num_descrs;
uint16_t last_modified_index; // Index in out_buffer when this object was last modified
uint32_t type_version;
JitOptDescrMapping *descrs;
} JitOptDescrObject;

typedef union _jit_opt_symbol {
uint8_t tag;
JitOptKnownClass cls;
Expand All @@ -99,6 +129,7 @@ typedef union _jit_opt_symbol {
JitOptTuple tuple;
JitOptTruthiness truthiness;
JitOptCompactInt compact;
JitOptDescrObject descr;
JitOptPredicate predicate;
} JitOptSymbol;

Expand Down Expand Up @@ -128,6 +159,11 @@ typedef struct ty_arena {
JitOptSymbol arena[TY_ARENA_SIZE];
} ty_arena;

typedef struct descr_arena {
int descr_curr_number;
int descr_max_number;
JitOptDescrMapping arena[DESCR_ARENA_SIZE];
} descr_arena;

#ifdef __cplusplus
}
Expand Down
Loading
Loading