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 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
|
import sys
from rpython.annotator import model as annmodel
from rpython.rtyper.llannotation import lltype_to_annotation
from rpython.annotator.policy import AnnotatorPolicy
from rpython.flowspace.model import Variable, Constant
from rpython.jit.metainterp.typesystem import deref
from rpython.rlib import rgc
from rpython.rlib.jit import elidable, oopspec
from rpython.rlib.rarithmetic import r_longlong, r_ulonglong, r_uint, intmask
from rpython.rlib.rarithmetic import LONG_BIT
from rpython.rtyper import rlist
from rpython.rtyper.lltypesystem import rlist as rlist_ll
from rpython.rtyper.annlowlevel import MixLevelHelperAnnotator
from rpython.rtyper.extregistry import ExtRegistryEntry
from rpython.rtyper.llinterp import LLInterpreter
from rpython.rtyper.lltypesystem import lltype, rffi, llmemory, rstr as ll_rstr, rdict as ll_rdict
from rpython.rtyper import rclass
from rpython.rtyper.lltypesystem import rordereddict
from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.rtyper.lltypesystem.module import ll_math
from rpython.translator.translator import TranslationContext
from rpython.translator.unsimplify import split_block
def getargtypes(annotator, values):
if values is None: # for backend tests producing stand-alone exe's
from rpython.annotator.listdef import s_list_of_strings
return [s_list_of_strings]
return [_annotation(annotator, x) for x in values]
def _annotation(a, x):
T = lltype.typeOf(x)
if T == lltype.Ptr(ll_rstr.STR):
t = str
else:
t = lltype_to_annotation(T)
return a.typeannotation(t)
def annotate(func, values, inline=None, backendoptimize=True,
translationoptions={}):
# build the normal ll graphs for ll_function
t = TranslationContext()
for key, value in translationoptions.items():
setattr(t.config.translation, key, value)
annpolicy = AnnotatorPolicy()
a = t.buildannotator(policy=annpolicy)
argtypes = getargtypes(a, values)
a.build_types(func, argtypes, main_entry_point=True)
rtyper = t.buildrtyper()
rtyper.specialize()
#if inline:
# auto_inlining(t, threshold=inline)
if backendoptimize:
from rpython.translator.backendopt.all import backend_optimizations
backend_optimizations(t, inline_threshold=inline or 0,
remove_asserts=True, really_remove_asserts=True)
return rtyper
def getgraph(func, values):
rtyper = annotate(func, values)
return rtyper.annotator.translator.graphs[0]
def autodetect_jit_markers_redvars(graph):
# the idea is to find all the jit_merge_point and
# add all the variables across the links to the reds.
for block, op in graph.iterblockops():
if op.opname == 'jit_marker':
jitdriver = op.args[1].value
if not jitdriver.autoreds:
continue
# if we want to support also can_enter_jit, we should find a
# way to detect a consistent set of red vars to pass *both* to
# jit_merge_point and can_enter_jit. The current simple
# solution doesn't work because can_enter_jit might be in
# another block, so the set of alive_v will be different.
methname = op.args[0].value
assert methname == 'jit_merge_point', (
"reds='auto' is supported only for jit drivers which "
"calls only jit_merge_point. Found a call to %s" % methname)
#
# compute the set of live variables across the jit_marker
alive_v = set()
for link in block.exits:
alive_v.update(link.args)
alive_v.difference_update(link.getextravars())
for op1 in block.operations[::-1]:
if op1 is op:
break # stop when the meet the jit_marker
alive_v.discard(op1.result)
alive_v.update(op1.args)
greens_v = op.args[2:]
reds_v = alive_v - set(greens_v)
reds_v = [v for v in reds_v if isinstance(v, Variable) and
v.concretetype is not lltype.Void]
reds_v = sort_vars(reds_v)
op.args.extend(reds_v)
if jitdriver.numreds is None:
jitdriver.numreds = len(reds_v)
elif jitdriver.numreds != len(reds_v):
raise AssertionError("there are multiple jit_merge_points "
"with the same jitdriver")
def split_before_jit_merge_point(graph, portalblock, portalopindex):
"""Split the block just before the 'jit_merge_point',
making sure the input args are in the canonical order.
"""
# split the block just before the jit_merge_point()
if portalopindex > 0:
link = split_block(portalblock, portalopindex)
portalblock = link.target
portalop = portalblock.operations[0]
# split again, this time enforcing the order of the live vars
# specified by decode_hp_hint_args().
assert portalop.opname == 'jit_marker'
assert portalop.args[0].value == 'jit_merge_point'
greens_v, reds_v = decode_hp_hint_args(portalop)
link = split_block(portalblock, 0, greens_v + reds_v)
return link.target
def sort_vars(args_v):
from rpython.jit.metainterp.history import getkind
_kind2count = {'int': 1, 'ref': 2, 'float': 3}
return sorted(args_v, key=lambda v: _kind2count[getkind(v.concretetype)])
def decode_hp_hint_args(op):
# Returns (list-of-green-vars, list-of-red-vars) without Voids.
# Both lists must be sorted: first INT, then REF, then FLOAT.
assert op.opname == 'jit_marker'
jitdriver = op.args[1].value
numgreens = len(jitdriver.greens)
assert jitdriver.numreds is not None
numreds = jitdriver.numreds
greens_v = op.args[2:2+numgreens]
reds_v = op.args[2+numgreens:]
assert len(reds_v) == numreds
#
def _sort(args_v, is_green):
lst = [v for v in args_v if v.concretetype is not lltype.Void]
if is_green:
assert len(lst) == len(args_v), (
"not supported so far: 'greens' variables contain Void")
# a crash here means that you have to reorder the variable named in
# the JitDriver. Indeed, greens and reds must both be sorted: first
# all INTs, followed by all REFs, followed by all FLOATs.
lst2 = sort_vars(lst)
assert lst == lst2
return lst
#
return (_sort(greens_v, True), _sort(reds_v, False))
def maybe_on_top_of_llinterp(rtyper, fnptr):
# Run a generated graph on top of the llinterp for testing.
# When translated, this just returns the fnptr.
funcobj = fnptr._obj
if hasattr(funcobj, 'graph'):
llinterp = LLInterpreter(rtyper) #, exc_data_ptr=exc_data_ptr)
def on_top_of_llinterp(*args):
return llinterp.eval_graph(funcobj.graph, list(args))
else:
assert hasattr(funcobj, '_callable')
def on_top_of_llinterp(*args):
return funcobj._callable(*args)
return on_top_of_llinterp
class Entry(ExtRegistryEntry):
_about_ = maybe_on_top_of_llinterp
def compute_result_annotation(self, s_rtyper, s_fnptr):
return s_fnptr
def specialize_call(self, hop):
hop.exception_cannot_occur()
return hop.inputarg(hop.args_r[1], arg=1)
# ____________________________________________________________
#
# Manually map oopspec'ed operations back to their ll implementation
# coming from modules like rpython.rtyper.rlist. The following
# functions are fished from the globals() by setup_extra_builtin().
def _ll_0_newlist(LIST):
return LIST.ll_newlist(0)
def _ll_1_newlist(LIST, count):
return LIST.ll_newlist(count)
_ll_0_newlist.need_result_type = True
_ll_1_newlist.need_result_type = True
_ll_1_newlist_clear = rlist._ll_alloc_and_clear
_ll_1_newlist_clear.need_result_type = True
def _ll_1_newlist_hint(LIST, hint):
return LIST.ll_newlist_hint(hint)
_ll_1_newlist_hint.need_result_type = True
def _ll_1_list_len(l):
return l.ll_length()
def _ll_2_list_getitem(l, index):
return rlist.ll_getitem(rlist.dum_checkidx, l, index)
def _ll_3_list_setitem(l, index, newitem):
rlist.ll_setitem(rlist.dum_checkidx, l, index, newitem)
def _ll_2_list_delitem(l, index):
rlist.ll_delitem(rlist.dum_checkidx, l, index)
def _ll_1_list_pop(l):
return rlist.ll_pop_default(rlist.dum_checkidx, l)
def _ll_2_list_pop(l, index):
return rlist.ll_pop(rlist.dum_checkidx, l, index)
_ll_2_list_append = rlist.ll_append
_ll_2_list_extend = rlist.ll_extend
_ll_3_list_insert = rlist.ll_insert_nonneg
_ll_2_list_delslice_startonly = rlist.ll_listdelslice_startonly
_ll_3_list_delslice_startstop = rlist.ll_listdelslice_startstop
_ll_2_list_inplace_mul = rlist.ll_inplace_mul
_ll_2_list_getitem_foldable = _ll_2_list_getitem
_ll_1_list_len_foldable = _ll_1_list_len
_ll_5_list_ll_arraycopy = rgc.ll_arraycopy
_ll_3_list_resize_hint_really = rlist_ll._ll_list_resize_hint_really
@elidable
def _ll_1_gc_identityhash(x):
return lltype.identityhash(x)
# the following function should not be "@elidable": I can think of
# a corner case in which id(const) is constant-folded, and then 'const'
# disappears and is collected too early (possibly causing another object
# with the same id() to appear).
def _ll_1_gc_id(ptr):
return llop.gc_id(lltype.Signed, ptr)
def _ll_1_gc_pin(ptr):
return llop.gc_pin(lltype.Bool, ptr)
def _ll_1_gc_unpin(ptr):
llop.gc_unpin(lltype.Void, ptr)
@oopspec("jit.force_virtual(inst)")
def _ll_1_jit_force_virtual(inst):
return llop.jit_force_virtual(lltype.typeOf(inst), inst)
def _ll_1_int_abs(x):
# this version doesn't branch
mask = x >> (LONG_BIT - 1)
return (x ^ mask) - mask
def _ll_2_int_floordiv(x, y):
# this is used only if the RPython program uses llop.int_floordiv()
# explicitly. For 'a // b', see _handle_int_special() in jtransform.py.
# This is the reverse of rpython.rtyper.rint.ll_int_py_div(), i.e.
# the same logic as rpython.rtyper.lltypesystem.opimpl.op_int_floordiv
# but written in a no-branch style.
r = x // y
p = r * y
# the JIT knows that if x and y are both positive, this is just 'r'
return r + (((x ^ y) >> (LONG_BIT - 1)) & (p != x))
def _ll_2_int_mod(x, y):
# same comments as _ll_2_int_floordiv()
r = x % y
# the JIT knows that if x and y are both positive, this doesn't change 'r'
r -= y & (((x ^ y) & (r | -r)) >> (LONG_BIT - 1))
return r
def _ll_1_cast_uint_to_float(x):
# XXX on 32-bit platforms, this should be done using cast_longlong_to_float
# (which is a residual call right now in the x86 backend)
return llop.cast_uint_to_float(lltype.Float, x)
def _ll_1_cast_float_to_uint(x):
# XXX on 32-bit platforms, this should be done using cast_float_to_longlong
# (which is a residual call right now in the x86 backend)
return llop.cast_float_to_uint(lltype.Unsigned, x)
def _ll_0_ll_read_timestamp():
from rpython.rlib import rtimer
return rtimer.read_timestamp()
# math support
# ------------
_ll_1_ll_math_ll_math_sqrt = ll_math.ll_math_sqrt
# long long support
# -----------------
def u_to_longlong(x):
return rffi.cast(lltype.SignedLongLong, x)
def _ll_1_llong_invert(xll):
y = ~r_ulonglong(xll)
return u_to_longlong(y)
def _ll_1_ullong_invert(xull):
return ~xull
def _ll_2_llong_lt(xll, yll):
return xll < yll
def _ll_2_llong_le(xll, yll):
return xll <= yll
def _ll_2_llong_eq(xll, yll):
return xll == yll
def _ll_2_llong_ne(xll, yll):
return xll != yll
def _ll_2_llong_gt(xll, yll):
return xll > yll
def _ll_2_llong_ge(xll, yll):
return xll >= yll
def _ll_2_ullong_eq(xull, yull):
return xull == yull
def _ll_2_ullong_ne(xull, yull):
return xull != yull
def _ll_2_ullong_ult(xull, yull):
return xull < yull
def _ll_2_ullong_ule(xull, yull):
return xull <= yull
def _ll_2_ullong_ugt(xull, yull):
return xull > yull
def _ll_2_ullong_uge(xull, yull):
return xull >= yull
def _ll_2_llong_add(xll, yll):
z = r_ulonglong(xll) + r_ulonglong(yll)
return u_to_longlong(z)
def _ll_2_llong_sub(xll, yll):
z = r_ulonglong(xll) - r_ulonglong(yll)
return u_to_longlong(z)
def _ll_2_llong_mul(xll, yll):
z = r_ulonglong(xll) * r_ulonglong(yll)
return u_to_longlong(z)
def _ll_2_llong_and(xll, yll):
z = r_ulonglong(xll) & r_ulonglong(yll)
return u_to_longlong(z)
def _ll_2_llong_or(xll, yll):
z = r_ulonglong(xll) | r_ulonglong(yll)
return u_to_longlong(z)
def _ll_2_llong_xor(xll, yll):
z = r_ulonglong(xll) ^ r_ulonglong(yll)
return u_to_longlong(z)
def _ll_2_ullong_add(xull, yull):
z = (xull) + (yull)
return (z)
def _ll_2_ullong_sub(xull, yull):
z = (xull) - (yull)
return (z)
def _ll_2_ullong_mul(xull, yull):
z = (xull) * (yull)
return (z)
def _ll_2_ullong_and(xull, yull):
z = (xull) & (yull)
return (z)
def _ll_2_ullong_or(xull, yull):
z = (xull) | (yull)
return (z)
def _ll_2_ullong_xor(xull, yull):
z = (xull) ^ (yull)
return (z)
def _ll_2_llong_lshift(xll, y):
z = r_ulonglong(xll) << y
return u_to_longlong(z)
def _ll_2_ullong_lshift(xull, y):
return xull << y
def _ll_2_llong_rshift(xll, y):
return xll >> y
def _ll_2_ullong_urshift(xull, y):
return xull >> y
def _ll_1_llong_from_int(x):
return r_longlong(intmask(x))
def _ll_1_ullong_from_int(x):
return r_ulonglong(intmask(x))
def _ll_1_llong_from_uint(x):
return r_longlong(r_uint(x))
def _ll_1_ullong_from_uint(x):
return r_ulonglong(r_uint(x))
def _ll_1_llong_to_int(xll):
return intmask(xll)
def _ll_1_llong_from_float(xf):
return r_longlong(xf)
def _ll_1_ullong_from_float(xf):
return r_ulonglong(xf)
def _ll_1_llong_to_float(xll):
return float(rffi.cast(lltype.SignedLongLong, xll))
def _ll_1_ullong_u_to_float(xull):
return float(rffi.cast(lltype.UnsignedLongLong, xull))
def _ll_1_llong_abs(xll):
if xll < 0:
return -xll
else:
return xll
# in the following calls to builtins, the JIT is allowed to look inside:
inline_calls_to = [
('int_abs', [lltype.Signed], lltype.Signed),
('int_floordiv', [lltype.Signed, lltype.Signed], lltype.Signed),
('int_mod', [lltype.Signed, lltype.Signed], lltype.Signed),
('ll_math.ll_math_sqrt', [lltype.Float], lltype.Float),
]
class LLtypeHelpers:
# ---------- dict ----------
_ll_1_dict_copy = ll_rdict.ll_copy
_ll_1_dict_clear = ll_rdict.ll_clear
_ll_2_dict_update = ll_rdict.ll_update
# ---------- dict keys(), values(), items(), iter ----------
_ll_1_dict_keys = ll_rdict.ll_dict_keys
_ll_1_dict_values = ll_rdict.ll_dict_values
_ll_1_dict_items = ll_rdict.ll_dict_items
_ll_1_dict_keys .need_result_type = True
_ll_1_dict_values.need_result_type = True
_ll_1_dict_items .need_result_type = True
_ll_1_dictiter_next = ll_rdict._ll_dictnext
_ll_1_dict_resize = ll_rdict.ll_dict_resize
# ---------- ordered dict ----------
_ll_1_odict_copy = rordereddict.ll_dict_copy
_ll_1_odict_clear = rordereddict.ll_dict_clear
_ll_2_odict_update = rordereddict.ll_dict_update
_ll_1_odict_keys = rordereddict.ll_dict_keys
_ll_1_odict_values = rordereddict.ll_dict_values
_ll_1_odict_items = rordereddict.ll_dict_items
_ll_1_odict_keys .need_result_type = True
_ll_1_odict_values.need_result_type = True
_ll_1_odict_items .need_result_type = True
_ll_1_odictiter_next = rordereddict._ll_dictnext
_ll_1_odict_resize = rordereddict.ll_dict_resize
# ---------- strings and unicode ----------
_ll_1_str_str2unicode = ll_rstr.LLHelpers.ll_str2unicode
def _ll_4_str_eq_slice_checknull(s1, start, length, s2):
"""str1[start : start + length] == str2."""
if not s2:
return 0
chars2 = s2.chars
if len(chars2) != length:
return 0
j = 0
chars1 = s1.chars
while j < length:
if chars1[start + j] != chars2[j]:
return 0
j += 1
return 1
def _ll_4_str_eq_slice_nonnull(s1, start, length, s2):
"""str1[start : start + length] == str2, assuming str2 != NULL."""
chars2 = s2.chars
if len(chars2) != length:
return 0
j = 0
chars1 = s1.chars
while j < length:
if chars1[start + j] != chars2[j]:
return 0
j += 1
return 1
def _ll_4_str_eq_slice_char(s1, start, length, c2):
"""str1[start : start + length] == c2."""
if length != 1:
return 0
if s1.chars[start] != c2:
return 0
return 1
def _ll_2_str_eq_nonnull(s1, s2):
len1 = len(s1.chars)
len2 = len(s2.chars)
if len1 != len2:
return 0
j = 0
chars1 = s1.chars
chars2 = s2.chars
while j < len1:
if chars1[j] != chars2[j]:
return 0
j += 1
return 1
def _ll_2_str_eq_nonnull_char(s1, c2):
chars = s1.chars
if len(chars) != 1:
return 0
if chars[0] != c2:
return 0
return 1
def _ll_2_str_eq_checknull_char(s1, c2):
if not s1:
return 0
chars = s1.chars
if len(chars) != 1:
return 0
if chars[0] != c2:
return 0
return 1
def _ll_2_str_eq_lengthok(s1, s2):
j = 0
chars1 = s1.chars
chars2 = s2.chars
len1 = len(chars1)
while j < len1:
if chars1[j] != chars2[j]:
return 0
j += 1
return 1
# ---------- malloc with del ----------
def _ll_2_raw_malloc(TP, size):
return lltype.malloc(TP, size, flavor='raw')
def build_ll_0_alloc_with_del(RESULT, vtable):
def _ll_0_alloc_with_del():
p = lltype.malloc(RESULT.TO)
lltype.cast_pointer(rclass.OBJECTPTR, p).typeptr = vtable
return p
return _ll_0_alloc_with_del
def build_raw_malloc_varsize_builder(zero=False,
add_memory_pressure=False,
track_allocation=True):
def build_ll_1_raw_malloc_varsize(ARRAY):
def _ll_1_raw_malloc_varsize(n):
return lltype.malloc(ARRAY, n, flavor='raw', zero=zero,
add_memory_pressure=add_memory_pressure,
track_allocation=track_allocation)
name = '_ll_1_raw_malloc_varsize'
if zero:
name += '_zero'
if add_memory_pressure:
name += '_mpressure'
if not track_allocation:
name += '_notrack'
_ll_1_raw_malloc_varsize.func_name = name
return _ll_1_raw_malloc_varsize
return build_ll_1_raw_malloc_varsize
build_ll_1_raw_malloc_varsize = (
build_raw_malloc_varsize_builder())
build_ll_1_raw_malloc_varsize_zero = (
build_raw_malloc_varsize_builder(zero=True))
build_ll_1_raw_malloc_varsize_zero_add_memory_pressure = (
build_raw_malloc_varsize_builder(zero=True, add_memory_pressure=True))
build_ll_1_raw_malloc_varsize_add_memory_pressure = (
build_raw_malloc_varsize_builder(add_memory_pressure=True))
build_ll_1_raw_malloc_varsize_no_track_allocation = (
build_raw_malloc_varsize_builder(track_allocation=False))
build_ll_1_raw_malloc_varsize_zero_no_track_allocation = (
build_raw_malloc_varsize_builder(zero=True, track_allocation=False))
build_ll_1_raw_malloc_varsize_zero_add_memory_pressure_no_track_allocation = (
build_raw_malloc_varsize_builder(zero=True, add_memory_pressure=True, track_allocation=False))
build_ll_1_raw_malloc_varsize_add_memory_pressure_no_track_allocation = (
build_raw_malloc_varsize_builder(add_memory_pressure=True, track_allocation=False))
def build_raw_malloc_fixedsize_builder(zero=False,
add_memory_pressure=False,
track_allocation=True):
def build_ll_0_raw_malloc_fixedsize(STRUCT):
def _ll_0_raw_malloc_fixedsize():
return lltype.malloc(STRUCT, flavor='raw', zero=zero,
add_memory_pressure=add_memory_pressure,
track_allocation=track_allocation)
name = '_ll_0_raw_malloc_fixedsize'
if zero:
name += '_zero'
if add_memory_pressure:
name += '_mpressure'
if not track_allocation:
name += '_notrack'
_ll_0_raw_malloc_fixedsize.func_name = name
return _ll_0_raw_malloc_fixedsize
return build_ll_0_raw_malloc_fixedsize
build_ll_0_raw_malloc_fixedsize = (
build_raw_malloc_fixedsize_builder())
build_ll_0_raw_malloc_fixedsize_zero = (
build_raw_malloc_fixedsize_builder(zero=True))
build_ll_0_raw_malloc_fixedsize_zero_add_memory_pressure = (
build_raw_malloc_fixedsize_builder(zero=True, add_memory_pressure=True))
build_ll_0_raw_malloc_fixedsize_add_memory_pressure = (
build_raw_malloc_fixedsize_builder(add_memory_pressure=True))
build_ll_0_raw_malloc_fixedsize_no_track_allocation = (
build_raw_malloc_fixedsize_builder(track_allocation=False))
build_ll_0_raw_malloc_fixedsize_zero_no_track_allocation = (
build_raw_malloc_fixedsize_builder(zero=True, track_allocation=False))
build_ll_0_raw_malloc_fixedsize_zero_add_memory_pressure_no_track_allocation = (
build_raw_malloc_fixedsize_builder(zero=True, add_memory_pressure=True, track_allocation=False))
build_ll_0_raw_malloc_fixedsize_add_memory_pressure_no_track_allocation = (
build_raw_malloc_fixedsize_builder(add_memory_pressure=True, track_allocation=False))
def build_raw_free_builder(track_allocation=True):
def build_ll_1_raw_free(ARRAY):
def _ll_1_raw_free(p):
lltype.free(p, flavor='raw',
track_allocation=track_allocation)
return _ll_1_raw_free
return build_ll_1_raw_free
build_ll_1_raw_free = (
build_raw_free_builder())
build_ll_1_raw_free_no_track_allocation = (
build_raw_free_builder(track_allocation=False))
def _ll_1_threadlocalref_get(TP, offset):
return llop.threadlocalref_get(TP, offset)
_ll_1_threadlocalref_get.need_result_type = 'exact' # don't deref
def _ll_1_weakref_create(obj):
return llop.weakref_create(llmemory.WeakRefPtr, obj)
def _ll_1_weakref_deref(TP, obj):
return llop.weakref_deref(lltype.Ptr(TP), obj)
_ll_1_weakref_deref.need_result_type = True
def _ll_1_gc_add_memory_pressure(num):
llop.gc_add_memory_pressure(lltype.Void, num)
def setup_extra_builtin(rtyper, oopspec_name, nb_args, extra=None):
name = '_ll_%d_%s' % (nb_args, oopspec_name.replace('.', '_'))
if extra is not None:
name = 'build' + name
try:
wrapper = globals()[name]
except KeyError:
wrapper = getattr(LLtypeHelpers, name).im_func
if extra is not None:
wrapper = wrapper(*extra)
return wrapper
# # ____________________________________________________________
class Index:
def __init__(self, n):
self.n = n
def parse_oopspec(fnobj):
FUNCTYPE = lltype.typeOf(fnobj)
ll_func = fnobj._callable
nb_args = len(FUNCTYPE.ARGS)
argnames = ll_func.func_code.co_varnames[:nb_args]
# parse the oopspec and fill in the arguments
operation_name, args = ll_func.oopspec.split('(', 1)
assert args.endswith(')')
args = args[:-1] + ',' # trailing comma to force tuple syntax
if args.strip() == ',':
args = '()'
nb_args = len(argnames)
argname2index = dict(zip(argnames, [Index(n) for n in range(nb_args)]))
argtuple = eval(args, argname2index)
return operation_name, argtuple
def normalize_opargs(argtuple, opargs):
result = []
for obj in argtuple:
if isinstance(obj, Index):
result.append(opargs[obj.n])
else:
result.append(Constant(obj, lltype.typeOf(obj)))
return result
def get_call_oopspec_opargs(fnobj, opargs):
oopspec, argtuple = parse_oopspec(fnobj)
normalized_opargs = normalize_opargs(argtuple, opargs)
return oopspec, normalized_opargs
def get_identityhash_oopspec(op):
return 'gc_identityhash', op.args
def get_gcid_oopspec(op):
return 'gc_id', op.args
RENAMED_ADT_NAME = {
'list': {
'll_getitem_fast': 'getitem',
'll_setitem_fast': 'setitem',
'll_length': 'len',
},
}
def get_send_oopspec(SELFTYPE, name):
oopspec_name = SELFTYPE.oopspec_name
assert oopspec_name is not None
renamed = RENAMED_ADT_NAME.get(oopspec_name, {})
pubname = renamed.get(name, name)
oopspec = '%s.%s' % (oopspec_name, pubname)
return oopspec
def decode_builtin_call(op):
if op.opname == 'direct_call':
fnobj = op.args[0].value._obj
opargs = op.args[1:]
return get_call_oopspec_opargs(fnobj, opargs)
elif op.opname == 'gc_identityhash':
return get_identityhash_oopspec(op)
elif op.opname == 'gc_id':
return get_gcid_oopspec(op)
else:
raise ValueError(op.opname)
def builtin_func_for_spec(rtyper, oopspec_name, ll_args, ll_res,
extra=None, extrakey=None):
assert (extra is None) == (extrakey is None)
key = (oopspec_name, tuple(ll_args), ll_res, extrakey)
try:
return rtyper._builtin_func_for_spec_cache[key]
except (KeyError, AttributeError):
pass
args_s = [lltype_to_annotation(v) for v in ll_args]
if '.' not in oopspec_name: # 'newxxx' operations
LIST_OR_DICT = ll_res
else:
LIST_OR_DICT = ll_args[0]
s_result = lltype_to_annotation(ll_res)
impl = setup_extra_builtin(rtyper, oopspec_name, len(args_s), extra)
if getattr(impl, 'need_result_type', False):
if hasattr(rtyper, 'annotator'):
bk = rtyper.annotator.bookkeeper
ll_restype = ll_res
if impl.need_result_type != 'exact':
ll_restype = deref(ll_restype)
desc = bk.getdesc(ll_restype)
else:
class TestingDesc(object):
knowntype = int
pyobj = None
desc = TestingDesc()
args_s.insert(0, annmodel.SomePBC([desc]))
#
if hasattr(rtyper, 'annotator'): # regular case
mixlevelann = MixLevelHelperAnnotator(rtyper)
c_func = mixlevelann.constfunc(impl, args_s, s_result)
mixlevelann.finish()
else:
# for testing only
c_func = Constant(oopspec_name,
lltype.Ptr(lltype.FuncType(ll_args, ll_res)))
#
if not hasattr(rtyper, '_builtin_func_for_spec_cache'):
rtyper._builtin_func_for_spec_cache = {}
rtyper._builtin_func_for_spec_cache[key] = (c_func, LIST_OR_DICT)
#
return c_func, LIST_OR_DICT
|