Skip to content

Commit 70d7881

Browse files
authored
[mypyc] Refactor: make LoadMem not borrow by default (#19445)
Borrowing is a dangerous default. It can only be used in very specific circumstances, so it shouldn't be the default. This is also arguably more consistent with other read ops which don't borrow by default.
1 parent 38cdacf commit 70d7881

File tree

12 files changed

+35
-32
lines changed

12 files changed

+35
-32
lines changed

mypyc/codegen/emitfunc.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,8 @@ def visit_load_mem(self, op: LoadMem) -> None:
793793
# TODO: we shouldn't dereference to type that are pointer type so far
794794
type = self.ctype(op.type)
795795
self.emit_line(f"{dest} = *({type} *){src};")
796+
if not op.is_borrowed:
797+
self.emit_inc_ref(dest, op.type)
796798

797799
def visit_set_mem(self, op: SetMem) -> None:
798800
dest = self.reg(op.dest)

mypyc/ir/ops.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1579,14 +1579,13 @@ class LoadMem(RegisterOp):
15791579

15801580
error_kind = ERR_NEVER
15811581

1582-
def __init__(self, type: RType, src: Value, line: int = -1) -> None:
1582+
def __init__(self, type: RType, src: Value, line: int = -1, *, borrow: bool = False) -> None:
15831583
super().__init__(line)
15841584
self.type = type
1585-
# TODO: for now we enforce that the src memory address should be Py_ssize_t
1586-
# later we should also support same width unsigned int
1585+
# TODO: Support other native integer types
15871586
assert is_pointer_rprimitive(src.type)
15881587
self.src = src
1589-
self.is_borrowed = True
1588+
self.is_borrowed = borrow and type.is_refcounted
15901589

15911590
def sources(self) -> list[Value]:
15921591
return [self.src]

mypyc/ir/pprint.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,9 @@ def visit_float_comparison_op(self, op: FloatComparisonOp) -> str:
267267
return self.format("%r = %r %s %r", op, op.lhs, op.op_str[op.op], op.rhs)
268268

269269
def visit_load_mem(self, op: LoadMem) -> str:
270-
return self.format("%r = load_mem %r :: %t*", op, op.src, op.type)
270+
return self.format(
271+
"%r = %sload_mem %r :: %t*", op, self.borrow_prefix(op), op.src, op.type
272+
)
271273

272274
def visit_set_mem(self, op: SetMem) -> str:
273275
return self.format("set_mem %r, %r :: %t*", op.dest, op.src, op.dest_type)

mypyc/irbuild/for_helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ def gen_condition(self) -> None:
733733

734734
def except_match() -> Value:
735735
addr = builder.add(LoadAddress(pointer_rprimitive, stop_async_iteration_op.src, line))
736-
return builder.add(LoadMem(stop_async_iteration_op.type, addr))
736+
return builder.add(LoadMem(stop_async_iteration_op.type, addr, borrow=True))
737737

738738
def try_body() -> None:
739739
awaitable = builder.call_c(anext_op, [builder.read(self.iter_target)], line)

mypyc/irbuild/ll_builder.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,9 @@ def goto_and_activate(self, block: BasicBlock) -> None:
286286
def keep_alive(self, values: list[Value], *, steal: bool = False) -> None:
287287
self.add(KeepAlive(values, steal=steal))
288288

289+
def load_mem(self, ptr: Value, value_type: RType, *, borrow: bool = False) -> Value:
290+
return self.add(LoadMem(value_type, ptr, borrow=borrow))
291+
289292
def push_error_handler(self, handler: BasicBlock | None) -> None:
290293
self.error_handlers.append(handler)
291294

@@ -660,7 +663,7 @@ def other() -> Value:
660663

661664
def get_type_of_obj(self, obj: Value, line: int) -> Value:
662665
ob_type_address = self.add(GetElementPtr(obj, PyObject, "ob_type", line))
663-
ob_type = self.add(LoadMem(object_rprimitive, ob_type_address))
666+
ob_type = self.load_mem(ob_type_address, object_rprimitive, borrow=True)
664667
self.add(KeepAlive([obj]))
665668
return ob_type
666669

@@ -2261,7 +2264,7 @@ def builtin_len(self, val: Value, line: int, use_pyssize_t: bool = False) -> Val
22612264
size_value = self.primitive_op(var_object_size, [val], line)
22622265
elif is_set_rprimitive(typ) or is_frozenset_rprimitive(typ):
22632266
elem_address = self.add(GetElementPtr(val, PySetObject, "used"))
2264-
size_value = self.add(LoadMem(c_pyssize_t_rprimitive, elem_address))
2267+
size_value = self.load_mem(elem_address, c_pyssize_t_rprimitive)
22652268
self.add(KeepAlive([val]))
22662269
elif is_dict_rprimitive(typ):
22672270
size_value = self.call_c(dict_ssize_t_size_op, [val], line)

mypyc/lower/list_ops.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

33
from mypyc.common import PLATFORM_SIZE
4-
from mypyc.ir.ops import GetElementPtr, IncRef, Integer, IntOp, LoadMem, SetMem, Value
4+
from mypyc.ir.ops import GetElementPtr, Integer, IntOp, SetMem, Value
55
from mypyc.ir.rtypes import (
66
PyListObject,
77
c_pyssize_t_rprimitive,
@@ -42,7 +42,7 @@ def buf_init_item(builder: LowLevelIRBuilder, args: list[Value], line: int) -> V
4242
@lower_primitive_op("list_items")
4343
def list_items(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
4444
ob_item_ptr = builder.add(GetElementPtr(args[0], PyListObject, "ob_item", line))
45-
return builder.add(LoadMem(pointer_rprimitive, ob_item_ptr, line))
45+
return builder.load_mem(ob_item_ptr, pointer_rprimitive)
4646

4747

4848
def list_item_ptr(builder: LowLevelIRBuilder, obj: Value, index: Value, line: int) -> Value:
@@ -68,6 +68,4 @@ def list_item_ptr(builder: LowLevelIRBuilder, obj: Value, index: Value, line: in
6868
def list_get_item_unsafe(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
6969
index = builder.coerce(args[1], c_pyssize_t_rprimitive, line)
7070
item_ptr = list_item_ptr(builder, args[0], index, line)
71-
value = builder.add(LoadMem(object_rprimitive, item_ptr, line))
72-
builder.add(IncRef(value))
73-
return value
71+
return builder.load_mem(item_ptr, object_rprimitive)

mypyc/test-data/irbuild-classes.test

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ def f(x):
363363
L0:
364364
r0 = __main__.B :: type
365365
r1 = get_element_ptr x ob_type :: PyObject
366-
r2 = load_mem r1 :: builtins.object*
366+
r2 = borrow load_mem r1 :: builtins.object*
367367
keep_alive x
368368
r3 = r2 == r0
369369
if r3 goto L1 else goto L2 :: bool
@@ -402,7 +402,7 @@ def f(x):
402402
L0:
403403
r0 = __main__.A :: type
404404
r1 = get_element_ptr x ob_type :: PyObject
405-
r2 = load_mem r1 :: builtins.object*
405+
r2 = borrow load_mem r1 :: builtins.object*
406406
keep_alive x
407407
r3 = r2 == r0
408408
if r3 goto L1 else goto L2 :: bool
@@ -412,7 +412,7 @@ L1:
412412
L2:
413413
r5 = __main__.B :: type
414414
r6 = get_element_ptr x ob_type :: PyObject
415-
r7 = load_mem r6 :: builtins.object*
415+
r7 = borrow load_mem r6 :: builtins.object*
416416
keep_alive x
417417
r8 = r7 == r5
418418
r4 = r8
@@ -449,7 +449,7 @@ def f(x):
449449
L0:
450450
r0 = __main__.A :: type
451451
r1 = get_element_ptr x ob_type :: PyObject
452-
r2 = load_mem r1 :: builtins.object*
452+
r2 = borrow load_mem r1 :: builtins.object*
453453
keep_alive x
454454
r3 = r2 == r0
455455
if r3 goto L1 else goto L2 :: bool
@@ -459,7 +459,7 @@ L1:
459459
L2:
460460
r5 = __main__.R :: type
461461
r6 = get_element_ptr x ob_type :: PyObject
462-
r7 = load_mem r6 :: builtins.object*
462+
r7 = borrow load_mem r6 :: builtins.object*
463463
keep_alive x
464464
r8 = r7 == r5
465465
r4 = r8
@@ -500,7 +500,7 @@ def f(x):
500500
L0:
501501
r0 = __main__.A :: type
502502
r1 = get_element_ptr x ob_type :: PyObject
503-
r2 = load_mem r1 :: builtins.object*
503+
r2 = borrow load_mem r1 :: builtins.object*
504504
keep_alive x
505505
r3 = r2 == r0
506506
if r3 goto L1 else goto L2 :: bool
@@ -510,7 +510,7 @@ L1:
510510
L2:
511511
r5 = __main__.C :: type
512512
r6 = get_element_ptr x ob_type :: PyObject
513-
r7 = load_mem r6 :: builtins.object*
513+
r7 = borrow load_mem r6 :: builtins.object*
514514
keep_alive x
515515
r8 = r7 == r5
516516
r4 = r8

mypyc/test-data/irbuild-isinstance.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ L0:
7777
x = r0
7878
r1 = __main__.C :: type
7979
r2 = get_element_ptr x ob_type :: PyObject
80-
r3 = load_mem r2 :: builtins.object*
80+
r3 = borrow load_mem r2 :: builtins.object*
8181
keep_alive x
8282
r4 = r3 == r1
8383
if r4 goto L1 else goto L2 :: bool

mypyc/test-data/irbuild-optional.test

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ def get(o):
311311
L0:
312312
r0 = __main__.A :: type
313313
r1 = get_element_ptr o ob_type :: PyObject
314-
r2 = load_mem r1 :: builtins.object*
314+
r2 = borrow load_mem r1 :: builtins.object*
315315
keep_alive o
316316
r3 = r2 == r0
317317
if r3 goto L1 else goto L2 :: bool
@@ -390,7 +390,7 @@ def g(o):
390390
L0:
391391
r0 = __main__.A :: type
392392
r1 = get_element_ptr o ob_type :: PyObject
393-
r2 = load_mem r1 :: builtins.object*
393+
r2 = borrow load_mem r1 :: builtins.object*
394394
keep_alive o
395395
r3 = r2 == r0
396396
if r3 goto L1 else goto L2 :: bool
@@ -403,7 +403,7 @@ L1:
403403
L2:
404404
r8 = __main__.B :: type
405405
r9 = get_element_ptr o ob_type :: PyObject
406-
r10 = load_mem r9 :: builtins.object*
406+
r10 = borrow load_mem r9 :: builtins.object*
407407
keep_alive o
408408
r11 = r10 == r8
409409
if r11 goto L3 else goto L4 :: bool
@@ -456,7 +456,7 @@ def f(o):
456456
L0:
457457
r0 = __main__.A :: type
458458
r1 = get_element_ptr o ob_type :: PyObject
459-
r2 = load_mem r1 :: builtins.object*
459+
r2 = borrow load_mem r1 :: builtins.object*
460460
keep_alive o
461461
r3 = r2 == r0
462462
if r3 goto L1 else goto L2 :: bool
@@ -488,7 +488,7 @@ def g(o):
488488
L0:
489489
r0 = __main__.A :: type
490490
r1 = get_element_ptr o ob_type :: PyObject
491-
r2 = load_mem r1 :: builtins.object*
491+
r2 = borrow load_mem r1 :: builtins.object*
492492
keep_alive o
493493
r3 = r2 == r0
494494
if r3 goto L1 else goto L2 :: bool

mypyc/test-data/irbuild-singledispatch.test

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def f_obj.__call__(__mypyc_self__, arg):
5757
r27 :: bool
5858
L0:
5959
r0 = get_element_ptr arg ob_type :: PyObject
60-
r1 = load_mem r0 :: builtins.object*
60+
r1 = borrow load_mem r0 :: builtins.object*
6161
keep_alive arg
6262
r2 = __mypyc_self__.dispatch_cache
6363
r3 = CPyDict_GetWithNone(r2, r1)
@@ -82,7 +82,7 @@ L2:
8282
L3:
8383
r16 = load_address PyLong_Type
8484
r17 = get_element_ptr r6 ob_type :: PyObject
85-
r18 = load_mem r17 :: builtins.object*
85+
r18 = borrow load_mem r17 :: builtins.object*
8686
keep_alive r6
8787
r19 = r18 == r16
8888
if r19 goto L4 else goto L7 :: bool
@@ -195,7 +195,7 @@ def f_obj.__call__(__mypyc_self__, x):
195195
r24 :: None
196196
L0:
197197
r0 = get_element_ptr x ob_type :: PyObject
198-
r1 = load_mem r0 :: builtins.object*
198+
r1 = borrow load_mem r0 :: builtins.object*
199199
keep_alive x
200200
r2 = __mypyc_self__.dispatch_cache
201201
r3 = CPyDict_GetWithNone(r2, r1)
@@ -220,7 +220,7 @@ L2:
220220
L3:
221221
r16 = load_address PyLong_Type
222222
r17 = get_element_ptr r6 ob_type :: PyObject
223-
r18 = load_mem r17 :: builtins.object*
223+
r18 = borrow load_mem r17 :: builtins.object*
224224
keep_alive r6
225225
r19 = r18 == r16
226226
if r19 goto L4 else goto L5 :: bool

0 commit comments

Comments
 (0)