1# 2# %CopyrightBegin% 3# 4# Copyright Ericsson AB 1997-2019. All Rights Reserved. 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18# %CopyrightEnd% 19# 20 21# 22# Types that should never be used in specific operations. 23# 24 25FORBIDDEN_TYPES=hQ 26 27# 28# The instructions that follows are only known by the loader and the emulator. 29# They can be changed without recompiling old Beam files. 30# 31# Instructions starting with a "i_" prefix are instructions produced by 32# instruction transformations; thus, they never occur in BEAM files. 33# 34 35# The too_old_compiler/0 instruction is specially handled in beam_load.c 36# to produce a user-friendly message informing the user that the module 37# needs to be re-compiled with a modern compiler. 38 39too_old_compiler/0 40too_old_compiler | never() => 41 42# In R9C and earlier, the loader used to insert special instructions inside 43# the module_info/0,1 functions. (In R10B and later, the compiler inserts 44# an explicit call to an undocumented BIF, so that no loader trickery is 45# necessary.) Since the instructions don't work correctly in R12B, simply 46# refuse to load the module. 47 48func_info M=a a==am_module_info A=u==0 | label L | move n x==0 => too_old_compiler 49func_info M=a a==am_module_info A=u==1 | label L | move n x==0 => too_old_compiler 50 51# The undocumented and unsupported guard BIF is_constant/1 was removed 52# in R13. The is_constant/2 operation is marked as obsolete in genop.tab, 53# so the loader will automatically generate a too_old_compiler message 54# it is used, but we need to handle the is_constant/1 BIF specially here. 55 56bif1 Fail u$func:erlang:is_constant/1 Src Dst => too_old_compiler 57 58# Since the constant pool was introduced in R12B, empty tuples ({}) 59# are literals. Therefore we no longer need to allow put_tuple/2 60# with a tuple size of zero. 61 62put_tuple u==0 d => too_old_compiler 63 64# 65# All the other instructions. 66# 67 68%cold 69# An unaligned label. The address of an unaligned label must never be saved 70# on the stack or used in a context where it can be confused with an Erlang term. 71 72label L 73 74# An label aligned to a certain boundary. This is used in two cases: 75# 76# * When the label points to the start of a function, as the ErtsCodeInfo 77# struct must be word-aligned. 78# * When the address is stored on the stack or otherwise needs to be properly 79# tagged as a continuation pointer. 80aligned_label L t 81 82i_func_info I a a I 83int_code_end 84 85i_generic_breakpoint 86i_debug_breakpoint 87i_return_time_trace 88i_return_to_trace 89trace_jump W 90i_yield 91%hot 92 93return 94 95# 96# A tail call will not refer to the current function on error unless it's a 97# BIF, so we can omit the line instruction for non-BIFs. 98# 99 100move S X0=x==0 | line Loc | call_ext_last Ar Func=u$is_not_bif D => \ 101 move S X0 | call_ext_last Ar Func D 102move S X0=x==0 | line Loc | call_ext_only Ar Func=u$is_not_bif => \ 103 move S X0 | call_ext_only Ar Func 104 105move S X0=x==0 | line Loc | call_last Ar Func D => \ 106 move S X0 | call_last Ar Func D 107move S X0=x==0 | line Loc | call_only Ar Func => \ 108 move S X0 | call_only Ar Func 109 110# The line number in int_func_start/5 can be NIL. 111func_line n => empty_func_line 112 113empty_func_line 114func_line I 115 116line n => 117line I 118 119allocate t t? 120allocate_heap t I t? 121 122deallocate t 123 124init y 125 126trim N Remaining => i_trim N 127 128i_trim t 129 130test_heap I t? 131 132# Translate instructions generated by a compiler before OTP 24. 133allocate_zero Ns Live => allocate_heap_zero Ns u Live 134allocate_heap_zero Ns Nh Live => allocate_heap_zero(Ns, Nh, Live) 135 136init_yregs I * 137 138# Selecting values. 139 140# The size of the dispatch code for a jump table is about 40 141# bytes. Therefore we shouldn't use a jump table if there are too few 142# values. 143 144select_val S Fail=fn Size=u Rest=* | use_jump_tab(Size, Rest, 6) => \ 145 jump_tab(S, Fail, Size, Rest) 146is_integer Fail=f S | select_val S=s Fail=fn Size=u Rest=* | use_jump_tab(Size, Rest, 6) => \ 147 jump_tab(S, Fail, Size, Rest) 148 149is_integer TypeFail=f S | select_val S=s Fail=fn Size=u Rest=* | \ 150 mixed_types(Size, Rest) => \ 151 split_values(S, TypeFail, Fail, Size, Rest) 152 153select_val S Fail=fn Size=u Rest=* | mixed_types(Size, Rest) => \ 154 split_values(S, Fail, Fail, Size, Rest) 155 156is_integer Fail=f S | select_val S=d Fail=fn Size=u Rest=* | \ 157 fixed_size_values(Size, Rest) => select_val(S, Fail, Size, Rest) 158 159is_atom Fail=f S | select_val S=d Fail=fn Size=u Rest=* | \ 160 fixed_size_values(Size, Rest) => select_val(S, Fail, Size, Rest) 161 162select_val S Fail=fn Size=u Rest=* | floats_or_bignums(Size, Rest) => \ 163 select_literals(S, Fail, Size, Rest) 164 165select_val S Fail=fn Size=u Rest=* | fixed_size_values(Size, Rest) => \ 166 select_val(S, Fail, Size, Rest) 167 168is_tuple Fail=f S | select_tuple_arity S=d Fail=f Size=u Rest=* => \ 169 select_tuple_arity(S, Fail, Size, Rest) 170 171select_tuple_arity S=d Fail=f Size=u Rest=* => \ 172 select_tuple_arity(S, Fail, Size, Rest) 173 174i_select_val_bins s fn I * 175 176i_select_val_lins s fn I * 177 178i_select_tuple_arity S f? I * 179 180i_jump_on_val s fn W I * 181 182is_number f? s 183 184jump f 185 186 187# 188# List matching instructions. The combination of test for a nonempty list followed 189# by get_{list/hd/tl} are common, so we will optimize that. 190# 191is_nonempty_list Fail nqia => jump Fail 192is_nonempty_list Fail Src | get_list Src Hd Tl => is_nonempty_list_get_list Fail Src Hd Tl 193is_nonempty_list Fail Src | get_hd Src Hd => is_nonempty_list_get_hd Fail Src Hd 194is_nonempty_list Fail Src | get_tl Src Tl => is_nonempty_list_get_tl Fail Src Tl 195 196is_nonempty_list f? S 197 198get_list S d d 199get_hd S d 200get_tl S d 201 202is_nonempty_list_get_list f S d d 203is_nonempty_list_get_hd f S d 204is_nonempty_list_get_tl f S d 205 206# Old-style catch. 207catch y f 208catch_end y 209 210# Try/catch. 211try Y F => catch Y F 212 213try_case y 214try_end y 215 216try_case_end s 217 218# Destructive set tuple element 219 220set_tuple_element s S P 221 222# 223# Get tuple element. Since this instruction is frequently used, we will try 224# to only fetch the pointer to the tuple once for a sequence of BEAM instructions 225# that fetch multiple elements from the same tuple. 226# 227 228current_tuple/1 229current_tuple/2 230 231is_tuple Fail=f Src | test_arity Fail Src Arity => \ 232 i_is_tuple_of_arity Fail Src Arity | current_tuple Src 233 234test_arity Fail Src Arity => i_test_arity Fail Src Arity | current_tuple Src 235 236is_tuple NotTupleFail Tuple | is_tagged_tuple WrongRecordFail Tuple Arity Atom => \ 237 i_is_tagged_tuple_ff NotTupleFail WrongRecordFail Tuple Arity Atom | current_tuple Tuple 238 239is_tagged_tuple Fail Tuple Arity Atom => \ 240 i_is_tagged_tuple Fail Tuple Arity Atom | current_tuple Tuple 241 242is_tuple Fail=f Src => i_is_tuple Fail Src | current_tuple Src 243 244i_is_tuple_of_arity f? s A 245i_test_arity f? s A 246 247i_is_tagged_tuple f? s A a 248i_is_tagged_tuple_ff f? f? s A a 249 250i_is_tuple f? s 251 252# Generate instruction sequence for fetching the tuple element and remember 253# that we have a current tuple pointer. 254 255get_tuple_element Tuple Pos Dst => \ 256 load_tuple_ptr Tuple | i_get_tuple_element Tuple Pos Dst | current_tuple Tuple 257current_tuple Tuple | get_tuple_element Tuple Pos Dst => \ 258 i_get_tuple_element Tuple Pos Dst | current_tuple Tuple 259 260# Drop the current_tuple instruction if the tuple is overwritten. 261i_get_tuple_element Tuple Pos Tuple | current_tuple Tuple => i_get_tuple_element Tuple Pos Tuple 262 263# This is a current_tuple instruction instruction not followed by get_tuple_element. 264# Invalidate the current tuple pointer. 265 266current_tuple Tuple => 267 268load_tuple_ptr s 269 270# If both positions and destinations are in consecutive memory, fetch and store 271# two words at once. 272i_get_tuple_element Tuple Pos1 Dst1 | current_tuple Tuple | \ 273 get_tuple_element Tuple Pos2 Dst2 | consecutive_words(Pos1, Dst1, Pos2, Dst2) => \ 274 get_two_tuple_elements Tuple Pos1 Dst1 Dst2 | current_tuple Tuple Dst2 275i_get_tuple_element Tuple Pos1 Dst1 | current_tuple Tuple | \ 276 get_tuple_element Tuple Pos2 Dst2 | consecutive_words(Pos1, Dst2, Pos2, Dst1) => \ 277 get_two_tuple_elements Tuple Pos1 Dst1 Dst2 | current_tuple Tuple Dst2 278 279# Drop the current_tuple instruction if the tuple is overwritten. 280current_tuple Tuple Tuple => 281current_tuple Tuple Dst => current_tuple Tuple 282 283# The first operand will only be used in the debug-compiled runtime 284# system to verify that the register holding the tuple pointer agrees 285# with the source tuple operand. 286i_get_tuple_element s P S 287get_two_tuple_elements s P S S 288 289# 290# Expection rasing instructions. Infrequently executed. 291# 292 293%cold 294case_end s 295 296badmatch s 297 298if_end 299 300raise s s 301 302# Workaround the limitation that generators must always return at least one instruction. 303delete_me/0 304delete_me => 305 306system_limit/1 307system_limit p => system_limit_body 308system_limit Fail=f => jump Fail 309 310system_limit_body 311 312%hot 313 314# 315# Optimize moves of consecutive memory addresses. 316# 317 318move Src=c Dst => i_move Src Dst 319 320move Src SrcDst | move SrcDst Dst => i_move Src SrcDst | move SrcDst Dst 321 322# Try to move two words at once. Always arrange the source operands in 323# consecutive order; the destination operands may be in consecutive or 324# reverse consecutive order. 325 326move S1=d D1=d | move S2=d D2=d | consecutive_words(S1, D1, S2, D2) => move_two_words S1 D1 S2 D2 327move S1=d D1=d | move S2=d D2=d | consecutive_words(S1, D2, S2, D1) => move_two_words S1 D1 S2 D2 328move S1=d D1=d | move S2=d D2=d | consecutive_words(S2, D1, S1, D2) => move_two_words S2 D2 S1 D1 329move S1=d D1=d | move S2=d D2=d | consecutive_words(S2, D2, S1, D1) => move_two_words S2 D2 S1 D1 330 331move Src Dst => i_move Src Dst 332 333# 334# Move instructions. 335# 336 337swap d d 338i_move s d 339move_two_words s d s d 340 341# 342# Receive operations. We conservatively align all labels before any 343# of the receive instructions. 344# 345# As the labels may be stored in the process structure, we must align them to 346# the nearest 4-byte boundary to ensure they're properly tagged as continuation 347# pointers. 348# 349 350label L | loop_rec Fail Reg => \ 351 aligned_label L u=4 | loop_rec Fail Reg 352label L | wait_timeout Fail Src => \ 353 aligned_label L u=4 | wait_timeout Fail Src 354label L | wait Fail => \ 355 aligned_label L u=4 | wait Fail 356label L | timeout => \ 357 aligned_label L u=4 | timeout 358 359loop_rec Fail x==0 | smp_mark_target_label(Fail) => i_loop_rec Fail 360 361aligned_label L A | wait_timeout Fail Src | smp_already_locked(L) => \ 362 aligned_label L A | wait_timeout_locked Src Fail 363wait_timeout Fail Src => wait_timeout_unlocked Src Fail 364 365aligned_label L A | wait Fail | smp_already_locked(L) => \ 366 aligned_label L A | wait_locked Fail 367wait Fail => wait_unlocked Fail 368 369aligned_label L A | timeout | smp_already_locked(L) => \ 370 aligned_label L A | timeout_locked 371 372remove_message 373timeout 374timeout_locked 375i_loop_rec f 376loop_rec_end f 377wait_locked f 378wait_unlocked f 379 380# Note that a timeout value must fit in 32 bits. 381wait_timeout_unlocked s f 382wait_timeout_locked s f 383 384send 385 386# 387# Optimized comparisons with one immediate/literal operand. 388# 389 390is_eq_exact Lbl S S => 391is_eq_exact Lbl C=c R=xy => is_eq_exact Lbl R C 392 393is_eq_exact Lbl R=xy n => is_nil Lbl R 394is_eq_exact Lbl R=xy C=ia => i_is_eq_exact_immed Lbl R C 395is_eq_exact Lbl R=xy C=q => is_eq_exact_literal(Lbl, R, C) 396 397is_ne_exact Lbl S S => jump Lbl 398is_ne_exact Lbl C=c R=xy => is_ne_exact Lbl R C 399 400is_ne_exact Lbl R=xy C=ian => i_is_ne_exact_immed Lbl R C 401is_ne_exact Lbl R=xy C=q => i_is_ne_exact_literal Lbl R C 402 403i_is_eq_exact_immed f? s c 404 405i_is_eq_exact_literal/4 406i_is_eq_exact_literal f? s c I 407 408i_is_ne_exact_immed f? s c 409 410i_is_ne_exact_literal f? s c 411 412is_eq_exact f? s s 413 414is_ne_exact f? s s 415 416is_lt f? s s 417is_ge f? s s 418 419is_eq Fail=f Const=c Reg=xy => is_eq Fail Reg Const 420is_eq f? s s 421 422is_ne Fail=f Const=c Reg=xy => is_ne Fail Reg Const 423is_ne f? s s 424 425# 426# Putting tuples. 427# 428# Code compiled with OTP 22 and later uses put_tuple2 to 429# to construct a tuple. 430# 431# Code compiled before OTP 22 uses put_tuple + one put instruction 432# per element. Translate to put_tuple2. 433# 434 435i_put_tuple/2 436put_tuple Arity Dst => i_put_tuple Dst u 437 438i_put_tuple Dst Arity Puts=* | put S1 | put S2 | \ 439 put S3 | put S4 | put S5 => \ 440 tuple_append_put5(Arity, Dst, Puts, S1, S2, S3, S4, S5) 441 442i_put_tuple Dst Arity Puts=* | put S => \ 443 tuple_append_put(Arity, Dst, Puts, S) 444 445i_put_tuple Dst Arity Puts=* => put_tuple2 Dst Arity Puts 446 447put_tuple2 S A * 448 449# 450# Putting lists. 451# 452 453store_cons/2 454put_list Hd Tl Dst => put_cons Hd Tl | store_cons u=1 Dst 455store_cons Len Dst | put_list Hd Dst Dst | distinct(Dst, Hd) => combine_conses(Len, Dst, Hd) 456store_cons Len Dst | put_list Hd Dst OtherDst => store_cons Len Dst | append_cons u Hd | store_cons u=1 OtherDst 457 458put_cons s s 459append_cons I s 460store_cons I d 461 462# 463# Some more only used by the emulator 464# 465 466%cold 467normal_exit 468continue_exit 469call_bif W 470call_bif_mfa a a I 471call_nif W W W 472call_error_handler 473error_action_code 474return_trace 475%hot 476 477# 478# Type tests. Note that the operands for most type tests are `s` to 479# ensure that literal operands will work. The BEAM compiler starting 480# from OTP 22 will never emit type tests with literal operands even if 481# all optimizations are turned off, but loading unoptimized code from 482# older releases and code generated by alternative code generators. 483# 484 485is_integer f? s 486is_list f? s 487is_atom f? s 488is_float f? s 489 490is_nil Fail=f n => 491is_nil Fail=f qia => jump Fail 492is_nil f? S 493 494# XXX Deprecated. 495is_bitstr Fail Term => is_bitstring Fail Term 496 497is_binary f? s 498is_bitstring f? s 499 500is_reference f? s 501is_pid f? s 502is_port f? s 503 504is_boolean f? s 505 506is_function2 f? s s 507 508################################################################# 509# External function and bif calls. 510################################################################# 511 512# Expands into call_light_bif/2 513call_light_bif/1 514 515# 516# The load_nif/2 BIF is an instruction. 517# 518 519call_ext u==2 u$func:erlang:load_nif/2 => \ 520 i_load_nif 521call_ext_last u==2 u$func:erlang:load_nif/2 D => \ 522 i_load_nif | deallocate D | return 523call_ext_only u==2 u$func:erlang:load_nif/2 => \ 524 i_load_nif | return 525 526%cold 527i_load_nif 528%hot 529 530# 531# apply/2 is an instruction, not a BIF. 532# 533 534call_ext u==2 u$func:erlang:apply/2 => i_apply_fun 535call_ext_last u==2 u$func:erlang:apply/2 D => i_apply_fun_last D 536call_ext_only u==2 u$func:erlang:apply/2 => i_apply_fun_only 537 538# 539# The apply/3 BIF is an instruction. 540# 541 542call_ext u==3 u$func:erlang:apply/3 => i_apply 543call_ext_last u==3 u$func:erlang:apply/3 D => i_apply_last D 544call_ext_only u==3 u$func:erlang:apply/3 => i_apply_only 545 546# 547# The yield/0 BIF is an instruction 548# 549 550call_ext u==0 u$func:erlang:yield/0 => i_yield 551call_ext_last u==0 u$func:erlang:yield/0 D => i_yield | deallocate D | return 552call_ext_only u==0 u$func:erlang:yield/0 => i_yield | return 553 554# 555# The hibernate/3 BIF is an instruction. 556# 557call_ext u==3 u$func:erlang:hibernate/3 => i_hibernate 558call_ext_last u==3 u$func:erlang:hibernate/3 D => i_hibernate 559call_ext_only u==3 u$func:erlang:hibernate/3 => i_hibernate 560 561call_ext u==0 u$func:os:perf_counter/0 => \ 562 i_perf_counter 563call_ext_last u==0 u$func:os:perf_counter/0 D => \ 564 i_perf_counter | deallocate D | return 565call_ext_only u==0 u$func:os:perf_counter/0 => \ 566 i_perf_counter | return 567 568# 569# BIFs like process_info/1,2 require up-to-date information about the current 570# emulator state, which the ordinary call_light_bif instruction doesn't save. 571# 572 573call_ext u Bif=u$is_bif | is_heavy_bif(Bif) => \ 574 i_call_ext Bif 575call_ext_last u Bif=u$is_bif D | is_heavy_bif(Bif) => \ 576 i_call_ext Bif | deallocate D | return 577call_ext_only Ar=u Bif=u$is_bif | is_heavy_bif(Bif) => \ 578 allocate u Ar | i_call_ext Bif | deallocate u | return 579 580# 581# The general case for BIFs that have no special requirements. 582# 583 584call_ext u Bif=u$is_bif => \ 585 call_light_bif Bif 586call_ext_last u Bif=u$is_bif D => \ 587 call_light_bif Bif | deallocate D | return 588call_ext_only Ar=u Bif=u$is_bif => \ 589 allocate u Ar | call_light_bif Bif | deallocate u | return 590 591# 592# Any remaining calls are calls to Erlang functions, not BIFs. 593# We rename the instructions to internal names. This is necessary, 594# to avoid an end-less loop, because we want to call a few BIFs 595# with call instructions. 596# 597 598call_ext Ar Func => i_call_ext Func 599call_ext_last Ar Func D => i_call_ext_last Func D 600call_ext_only Ar Func => i_call_ext_only Func 601 602i_validate t 603 604i_apply 605i_apply_last t 606i_apply_only 607 608i_apply_fun 609i_apply_fun_last t 610i_apply_fun_only 611 612call_light_bif Bif => call_light_bif Bif Bif 613call_light_bif b e 614 615%cold 616 617i_hibernate 618i_perf_counter 619 620%hot 621 622# 623# Calls to non-building and guard BIFs. 624# 625 626bif0 u$bif:erlang:self/0 Dst=d => self Dst 627bif0 u$bif:erlang:node/0 Dst=d => node Dst 628 629bif1 Fail=f Bif=u$bif:erlang:hd/1 Src=n Dst => \ 630 jump Fail 631bif1 Fail=f Bif=u$bif:erlang:hd/1 Src Dst => \ 632 is_nonempty_list Fail Src | get_hd Src Dst 633bif1 Fail Bif=u$bif:erlang:hd/1 Src Dst => \ 634 bif_hd Fail Src Dst 635 636bif_hd j? s d 637 638bif1 Fail=f Bif=u$bif:erlang:tl/1 Src=n Dst => \ 639 jump Fail 640bif1 Fail=f Bif=u$bif:erlang:tl/1 Src Dst => \ 641 is_nonempty_list Fail Src | get_tl Src Dst 642 643bif1 Fail Bif=u$bif:erlang:get/1 Src=s Dst=d => get(Src, Dst) 644 645bif2 Fail u$bif:erlang:element/2 S1=ixy S2 Dst => bif_element Fail S1 S2 Dst 646 647bif_element j? s s d 648 649bif1 Fail Bif S1 Dst | never_fails(Bif) => nofail_bif1 S1 Bif Dst 650bif2 Fail Bif S1 S2 Dst | never_fails(Bif) => nofail_bif2 S1 S2 Bif Dst 651 652bif1 Fail Bif S1 Dst => i_bif1 S1 Fail Bif Dst 653bif2 Fail Bif S1 S2 Dst => i_bif2 S1 S2 Fail Bif Dst 654 655nofail_bif2 S1=d S2=ian Bif Dst | is_eq_exact_bif(Bif) => bif_is_eq_exact_immed S1 S2 Dst 656nofail_bif2 S1=d S2=ian Bif Dst | is_ne_exact_bif(Bif) => bif_is_ne_exact_immed S1 S2 Dst 657 658i_get_hash c I d 659i_get s d 660 661self d 662 663node d 664 665nofail_bif1 s b d 666nofail_bif2 s s b d 667 668i_bif1 s j? b d 669i_bif2 s s j? b d 670i_bif3 s s s j? b d 671 672bif_is_eq_exact_immed S c d 673bif_is_ne_exact_immed S c d 674 675# 676# Internal calls. 677# 678 679call Ar Func => i_call Func 680call_last Ar Func D => i_call_last Func D 681call_only Ar Func => i_call_only Func 682 683i_call f 684i_call_last f t 685i_call_only f 686 687i_call_ext e 688i_call_ext_last e t 689i_call_ext_only e 690 691# Fun calls. 692 693call_fun Arity | deallocate D | return => i_call_fun_last Arity D 694call_fun Arity => i_call_fun Arity 695 696i_call_fun t 697i_call_fun_last t t 698 699# 700# A fun with an empty environment can be converted to a literal. 701# As a further optimization, the we try to move the fun to its 702# final destination directly. 703 704make_fun2 OldIndex=u => make_fun2(OldIndex) 705make_fun3 OldIndex=u Dst=d NumFree=u Env=* => make_fun3(OldIndex, Dst, NumFree, Env) 706 707%cold 708 709i_make_fun3 F S t * 710 711# Psuedo-instruction for signalling lambda load errors. Never actually runs. 712i_lambda_error t 713 714%hot 715 716is_function f? S 717is_function Fail=f c => jump Fail 718 719# The start and end of a function. 720int_func_start/5 721int_func_end/0 722 723func_prologue/2 724 725int_func_start Func_Label Func_Line M F A | \ 726 label Entry_Label | line Entry_Line => \ 727 int_func_start Func_Label Func_Line M F A | \ 728 func_prologue Entry_Label Entry_Line 729 730int_func_start Func_Label Func_Line M F A | \ 731 label Entry_Label => \ 732 int_func_start Func_Label Func_Line M F A | \ 733 func_prologue Entry_Label n 734 735int_func_start Func_Label Func_Line M F A | \ 736 func_prologue Entry_Label Entry_Line | \ 737 is_mfa_bif(M, F, A) => \ 738 aligned_label Func_Label u=8 | \ 739 func_line Func_Line | \ 740 i_func_info Func_Label M F A | \ 741 aligned_label Entry_Label u=8 | \ 742 line Entry_Line | \ 743 i_breakpoint_trampoline | \ 744 call_bif_mfa M F A 745 746int_func_start Func_Label Func_Line M F A | \ 747 func_prologue Entry_Label Entry_Line => \ 748 aligned_label Func_Label u=8 | \ 749 func_line Func_Line | \ 750 i_func_info Func_Label M F A | \ 751 aligned_label Entry_Label u=8 | \ 752 line Entry_Line | \ 753 i_breakpoint_trampoline | \ 754 i_test_yield 755 756 757int_func_end | needs_nif_padding() => i_nif_padding 758int_func_end => 759 760# Handles yielding on function ingress (rather than on each call). 761i_test_yield 762 763# Ensures that the prior function is large enough to allow NIF patching. 764i_nif_padding 765 766# Handles tracing, early NIF calls, and so on. 767i_breakpoint_trampoline 768 769# ================================================================ 770# Bit syntax matching obsoleted in OTP 22. 771# ================================================================ 772 773%cold 774bs_start_match2 Fail=f ica X Y D => jump Fail 775bs_start_match2 Fail Bin X Y D => i_bs_start_match2 Bin Fail X Y D 776i_bs_start_match2 S f t t d 777 778bs_save2 Reg Index => bs_save(Reg, Index) 779i_bs_save2 x t 780 781bs_restore2 Reg Index => bs_restore(Reg, Index) 782i_bs_restore2 S t 783 784bs_context_to_binary S 785%warm 786 787# ================================================================ 788# New bit syntax matching (R11B). 789# ================================================================ 790 791%warm 792 793# Matching integers 794bs_match_string Fail Ms Bits Val => i_bs_match_string Ms Fail Bits Val 795 796i_bs_match_string S f W W 797 798# Fetching integers from binaries. 799bs_get_integer2 Fail=f Ms=xy Live=u Sz=sq Unit=u Flags=u Dst=d => \ 800 get_integer2(Fail, Ms, Live, Sz, Unit, Flags, Dst) 801 802i_bs_get_integer S f? t t s d 803 804i_bs_get_integer_8 S t f? d 805i_bs_get_integer_16 S t f? d 806i_bs_get_integer_32 S t f? d 807i_bs_get_integer_64 S t f? t d 808 809# Fetching binaries from binaries. 810bs_get_binary2 Fail=f Ms=xy Live=u Sz=sq Unit=u Flags=u Dst=d => \ 811 get_binary2(Fail, Ms, Live, Sz, Unit, Flags, Dst) 812 813i_bs_get_binary2 S f t? s t d 814i_bs_get_binary_all2 S f? t t d 815 816# Fetching float from binaries. 817bs_get_float2 Fail=f Ms=xy Live=u Sz=s Unit=u Flags=u Dst=d => \ 818 get_float2(Fail, Ms, Live, Sz, Unit, Flags, Dst) 819 820bs_get_float2 Fail=f Ms=x Live=u Sz=q Unit=u Flags=u Dst=d => jump Fail 821 822i_bs_get_float2 S f? t s t d 823 824# Miscellanous 825 826bs_skip_bits2 Fail=f Ms=xy Sz=sq Unit=u Flags=u => \ 827 skip_bits2(Fail, Ms, Sz, Unit, Flags) 828 829i_bs_skip_bits_imm2 f? S W 830i_bs_skip_bits2 S S f? t 831 832bs_test_tail2 f? S t 833 834bs_test_unit f? S t 835 836# Gets a bitstring from the tail of a context. 837bs_get_tail S d t 838 839# New bs_start_match variant for contexts with external position storage. 840# 841# bs_get/set_position is used to save positions into registers instead of 842# "slots" in the context itself, which lets us continue matching even after 843# we've passed it off to another function. 844 845bs_start_match4 a==am_no_fail Live=u Src=xy Ctx=d => \ 846 bs_start_match3 p Src Live Ctx 847bs_start_match4 Fail=f Live=u Src=xy Ctx=d => \ 848 bs_start_match3 Fail Src Live Ctx 849 850%if ARCH_64 851 852# This instruction nops on 64-bit platforms 853bs_start_match4 a==am_resume Live Same Same => 854bs_start_match4 a==am_resume Live Ctx Dst => move Ctx Dst 855 856%else 857 858bs_start_match4 a==am_resume Live Ctx Dst => \ 859 bs_start_match4 a=am_no_fail Live Ctx Dst 860 861%endif 862 863bs_start_match3 Fail=j ica Live Dst => jump Fail 864bs_start_match3 Fail Bin Live Dst => i_bs_start_match3 Bin Live Fail Dst 865 866i_bs_start_match3 S t j d 867 868# Match context position instructions. 64-bit assumes that all positions can 869# fit into an unsigned small. 870 871%if ARCH_64 872 bs_get_position Src Dst Live => i_bs_get_position Src Dst 873 i_bs_get_position S S 874 bs_set_position S S 875%else 876 bs_get_position S d t? 877 bs_set_position S S 878%endif 879 880# 881# Utf8/utf16/utf32 support. (R12B-5) 882# 883bs_get_utf8 Fail=f Ms=xy u u Dst=d => i_bs_get_utf8 Ms Fail Dst 884i_bs_get_utf8 S f? d 885 886bs_skip_utf8 Fail=f Ms=xy u u => i_bs_skip_utf8 Ms Fail 887i_bs_skip_utf8 S f? 888 889bs_get_utf16 Fail=f Ms=xy u Flags=u Dst=d => i_bs_get_utf16 Ms Fail Flags Dst 890bs_skip_utf16 Fail=f Ms=xy u Flags=u => i_bs_skip_utf16 Ms Fail Flags 891 892i_bs_get_utf16 S f? t d 893i_bs_skip_utf16 S f? t 894 895bs_get_utf32 Fail=f Ms=xy Live=u Flags=u Dst=d => \ 896 bs_get_integer2 Fail Ms Live i=32 u=1 Flags Dst | \ 897 i_bs_validate_unicode_retract Fail Dst Ms 898bs_skip_utf32 Fail=f Ms=xy Live=u Flags=u => \ 899 bs_get_integer2 Fail Ms Live i=32 u=1 Flags x | \ 900 i_bs_validate_unicode_retract Fail x Ms 901 902i_bs_validate_unicode_retract j s S 903%hot 904 905# 906# Constructing binaries 907# 908%warm 909 910bs_init2 Fail Sz Words Regs Flags Dst | binary_too_big(Sz) => system_limit Fail 911 912bs_init2 Fail Sz=u Words=u==0 Regs Flags Dst => i_bs_init Sz Regs Dst 913 914bs_init2 Fail Sz=u Words Regs Flags Dst => \ 915 i_bs_init_heap Sz Words Regs Dst 916 917bs_init2 Fail Sz Words=u==0 Regs Flags Dst => \ 918 i_bs_init_fail Sz Fail Regs Dst 919bs_init2 Fail Sz Words Regs Flags Dst => \ 920 i_bs_init_fail_heap Sz Words Fail Regs Dst 921 922i_bs_init_fail S j? t? S 923 924i_bs_init_fail_heap s I j? t? S 925 926i_bs_init W t? S 927 928i_bs_init_heap W I t? S 929 930 931bs_init_bits Fail Sz=o Words Regs Flags Dst => system_limit Fail 932 933bs_init_bits Fail Sz=u Words=u==0 Regs Flags Dst => \ 934 i_bs_init_bits Sz Regs Dst 935bs_init_bits Fail Sz=u Words Regs Flags Dst => \ 936 i_bs_init_bits_heap Sz Words Regs Dst 937 938bs_init_bits Fail Sz Words=u==0 Regs Flags Dst => \ 939 i_bs_init_bits_fail Sz Fail Regs Dst 940bs_init_bits Fail Sz Words Regs Flags Dst => \ 941 i_bs_init_bits_fail_heap Sz Words Fail Regs Dst 942 943i_bs_init_bits_fail S j? t? S 944 945i_bs_init_bits_fail_heap s I j? t? S 946 947i_bs_init_bits W t? S 948i_bs_init_bits_heap W I t? S 949 950bs_add Fail S1=i==0 S2 Unit=u==1 D => move S2 D 951 952bs_add j? s s t? x 953 954bs_append Fail Size Extra Live Unit Bin Flags Dst => \ 955 i_bs_append Fail Extra Live Unit Size Bin Dst 956 957bs_private_append Fail Size Unit Bin Flags Dst => \ 958 i_bs_private_append Fail Unit Size Bin Dst 959 960i_bs_private_append Fail Unit Size Bin Dst=y => \ 961 i_bs_private_append Fail Unit Size Bin x | move x Dst 962 963bs_init_writable 964 965i_bs_append j? I t? t s s S 966i_bs_private_append j? t s S x 967 968# 969# Storing integers into binaries. 970# 971 972bs_put_integer Fail=j Sz=sq Unit=u Flags=u Src=s => \ 973 put_integer(Fail, Sz, Unit, Flags, Src) 974 975i_new_bs_put_integer j? S t s 976i_new_bs_put_integer_imm s j? W t 977 978# 979# Utf8/utf16/utf32 support. (R12B-5) 980# 981 982bs_utf8_size j Src Dst=d => i_bs_utf8_size Src Dst 983bs_utf16_size j Src Dst=d => i_bs_utf16_size Src Dst 984 985bs_put_utf8 Fail u Src => i_bs_put_utf8 Fail Src 986 987bs_put_utf32 Fail=j Flags=u Src=s => \ 988 i_bs_validate_unicode Fail Src | bs_put_integer Fail i=32 u=1 Flags Src 989 990i_bs_utf8_size s x 991i_bs_utf16_size s x 992 993i_bs_put_utf8 j? s 994bs_put_utf16 j? t s 995 996i_bs_validate_unicode j? s 997 998# 999# Storing floats into binaries. 1000# 1001 1002# Will fail. No need to keep the instruction, because bs_add or 1003# bs_init* would already have raised an exception. 1004bs_put_float Fail Sz=q Unit Flags Val => 1005 1006bs_put_float Fail=j Sz=s Unit=u Flags=u Src=s => \ 1007 put_float(Fail, Sz, Unit, Flags, Src) 1008 1009i_new_bs_put_float j? S t s 1010i_new_bs_put_float_imm j? W t s 1011 1012# 1013# Storing binaries into binaries. 1014# 1015 1016bs_put_binary Fail=j Sz=s Unit=u Flags=u Src=s => \ 1017 put_binary(Fail, Sz, Unit, Flags, Src) 1018 1019i_new_bs_put_binary j? s t s 1020i_new_bs_put_binary_imm j? W s 1021i_new_bs_put_binary_all s j? t 1022 1023# 1024# Warning: The i_bs_put_string and i_new_bs_put_string instructions 1025# are specially treated in the loader. 1026# Don't change the instruction format unless you change the loader too. 1027# 1028 1029bs_put_string W W 1030 1031# 1032# New floating point instructions (R8). 1033# 1034 1035fadd p FR1 FR2 FR3 => i_fadd FR1 FR2 FR3 1036fsub p FR1 FR2 FR3 => i_fsub FR1 FR2 FR3 1037fmul p FR1 FR2 FR3 => i_fmul FR1 FR2 FR3 1038fdiv p FR1 FR2 FR3 => i_fdiv FR1 FR2 FR3 1039fnegate p FR1 FR2 => i_fnegate FR1 FR2 1040 1041fmove Arg=l Dst=d => fstore Arg Dst 1042fmove Arg=dq Dst=l => fload Arg Dst 1043 1044fstore l d 1045fload Sq l 1046 1047fconv s l 1048 1049i_fadd l l l 1050i_fsub l l l 1051i_fmul l l l 1052i_fdiv l l l 1053i_fnegate l l 1054 1055fclearerror => 1056fcheckerror p => 1057 1058%hot 1059 1060# 1061# New apply instructions in R10B. 1062# 1063 1064apply t 1065apply_last t t 1066 1067# 1068# Handle compatibility with OTP 17 here. 1069# 1070 1071i_put_map_assoc/4 1072 1073# We KNOW that in OTP 20 (actually OTP 18 and higher), a put_map_assoc instruction 1074# is always preceded by an is_map test. That means that put_map_assoc can never 1075# fail and does not need any failure label. 1076 1077put_map_assoc Fail Map Dst Live Size Rest=* | compiled_with_otp_20_or_higher() => \ 1078 i_put_map_assoc Map Dst Live Size Rest 1079 1080# Translate the put_map_assoc instruction if the module was compiled by a compiler 1081# before 20. This is only necessary if the OTP 17 compiler was used, but we 1082# have no safe and relatively easy way to know whether OTP 18/19 was used. 1083 1084put_map_assoc Fail=p Map Dst Live Size Rest=* => \ 1085 ensure_map Map | i_put_map_assoc Map Dst Live Size Rest 1086put_map_assoc Fail=f Map Dst Live Size Rest=* => \ 1087 is_map Fail Map | i_put_map_assoc Map Dst Live Size Rest 1088 1089ensure_map Lit=q | literal_is_map(Lit) => 1090 1091%cold 1092ensure_map s 1093%hot 1094 1095# 1096# Map instructions. First introduced in R17. 1097# 1098 1099sorted_put_map_assoc/4 1100i_put_map_assoc Map Dst Live Size Rest=* | map_key_sort(Size, Rest) => \ 1101 sorted_put_map_assoc Map Dst Live Size Rest 1102 1103sorted_put_map_exact/5 1104put_map_exact F Map Dst Live Size Rest=* | map_key_sort(Size, Rest) => \ 1105 sorted_put_map_exact F Map Dst Live Size Rest 1106 1107sorted_put_map_assoc Map Dst Live Size Rest=* | is_empty_map(Map) => \ 1108 new_map Dst Live Size Rest 1109sorted_put_map_assoc Src=s Dst Live Size Rest=* => \ 1110 update_map_assoc Src Dst Live Size Rest 1111 1112sorted_put_map_exact Fail Src Dst Live Size Rest=* => \ 1113 update_map_exact Src Fail Dst Live Size Rest 1114 1115new_map Dst Live Size Rest=* | is_small_map_literal_keys(Size, Rest) => \ 1116 new_small_map_lit(Dst, Live, Size, Rest) 1117 1118new_map d t I * 1119i_new_small_map_lit d t q I * 1120update_map_assoc s d t I * 1121update_map_exact s j? d t I * 1122 1123is_map f? s 1124 1125## Transform has_map_fields #{ K1 := _, K2 := _ } to has_map_elements 1126 1127has_map_fields Fail Src Size Rest=* => \ 1128 has_map_fields(Fail, Src, Size, Rest) 1129 1130## Transform get_map_elements(s) #{ K1 := V1, K2 := V2 } 1131 1132get_map_elements Fail Src Size=u==2 Rest=* => \ 1133 get_map_element(Fail, Src, Size, Rest) 1134get_map_elements Fail Src Size Rest=* | map_key_sort(Size, Rest) => \ 1135 get_map_elements(Fail, Src, Size, Rest) 1136 1137i_get_map_elements f? s I * 1138 1139i_get_map_element_hash Fail Src=c Key Hash Dst => \ 1140 move Src x | i_get_map_element_hash Fail x Key Hash Dst 1141i_get_map_element_hash f? S c I S 1142 1143i_get_map_element Fail Src=c Key Dst => \ 1144 move Src x | i_get_map_element Fail x Key Dst 1145i_get_map_element f? S S S 1146 1147# 1148# Convert the plus operations to a generic plus instruction. 1149# 1150gen_plus/5 1151gen_minus/5 1152 1153gc_bif1 Fail Live u$bif:erlang:splus/1 Src Dst => \ 1154 gen_plus Fail Live Src i Dst 1155gc_bif2 Fail Live u$bif:erlang:splus/2 S1 S2 Dst => \ 1156 gen_plus Fail Live S1 S2 Dst 1157 1158gc_bif1 Fail Live u$bif:erlang:sminus/1 Src Dst => \ 1159 i_unary_minus Src Fail Dst 1160gc_bif2 Fail Live u$bif:erlang:sminus/2 S1 S2 Dst => \ 1161 gen_minus Fail Live S1 S2 Dst 1162 1163# 1164# Optimize addition and subtraction of small literals using 1165# the i_increment/3 instruction (in bodies, not in guards). 1166# 1167 1168gen_plus p Live Int=i Reg=d Dst => \ 1169 increment(Reg, Int, Dst) 1170gen_plus p Live Reg=d Int=i Dst => \ 1171 increment(Reg, Int, Dst) 1172 1173gen_minus p Live Reg=d Int=i Dst | negation_is_small(Int) => \ 1174 increment_from_minus(Reg, Int, Dst) 1175 1176# 1177# Arithmetic instructions. 1178# 1179 1180# It is OK to swap arguments for '+' in a guard. It is also 1181# OK to turn minus into plus in a guard. 1182gen_plus Fail=f Live S1=c S2 Dst => i_plus S2 S1 Fail Dst 1183gen_minus Fail=f Live S1 S2=i Dst | negation_is_small(S2) => \ 1184 plus_from_minus(Fail, Live, S1, S2, Dst) 1185 1186gen_plus Fail Live S1 S2 Dst => i_plus S1 S2 Fail Dst 1187 1188gen_minus Fail Live S1 S2 Dst => i_minus S1 S2 Fail Dst 1189 1190gc_bif2 Fail Live u$bif:erlang:stimes/2 S1 S2 Dst => \ 1191 i_times Fail S1 S2 Dst 1192 1193gc_bif2 Fail Live u$bif:erlang:div/2 S1 S2 Dst => \ 1194 i_m_div Fail S1 S2 Dst 1195 1196# Fused 'rem'/'div' pair. 1197gc_bif2 Fail Live u$bif:erlang:rem/2 LHS RHS Remainder | \ 1198 gc_bif2 A B u$bif:erlang:intdiv/2 LHS RHS Quotient | \ 1199 distinct(LHS, Remainder) | \ 1200 distinct(RHS, Remainder) => \ 1201 i_rem_div LHS RHS Fail Remainder Quotient 1202 1203# As above but with a `line` in between 1204gc_bif2 Fail Live u$bif:erlang:rem/2 LHS RHS Remainder | \ 1205 line Loc | \ 1206 gc_bif2 A B u$bif:erlang:intdiv/2 LHS RHS Quotient | \ 1207 distinct(LHS, Remainder) | \ 1208 distinct(RHS, Remainder) => \ 1209 i_rem_div LHS RHS Fail Remainder Quotient 1210 1211# Fused 'div'/'rem' pair 1212gc_bif2 Fail Live u$bif:erlang:intdiv/2 LHS RHS Quotient | \ 1213 gc_bif2 A B u$bif:erlang:rem/2 LHS RHS Remainder | \ 1214 distinct(LHS, Quotient) | \ 1215 distinct(RHS, Quotient) => \ 1216 i_div_rem LHS RHS Fail Quotient Remainder 1217 1218# As above but with a `line` in between 1219gc_bif2 Fail Live u$bif:erlang:intdiv/2 LHS RHS Quotient | \ 1220 line Loc | \ 1221 gc_bif2 A B u$bif:erlang:rem/2 LHS RHS Remainder | \ 1222 distinct(LHS, Quotient) | \ 1223 distinct(RHS, Quotient) => \ 1224 i_div_rem LHS RHS Fail Quotient Remainder 1225 1226gc_bif2 Fail Live u$bif:erlang:intdiv/2 S1 S2 Dst => \ 1227 i_int_div Fail S1 S2 Dst 1228gc_bif2 Fail Live u$bif:erlang:rem/2 S1 S2 Dst => \ 1229 i_rem S1 S2 Fail Dst 1230 1231gc_bif2 Fail Live u$bif:erlang:bsl/2 S1 S2 Dst => \ 1232 i_bsl S1 S2 Fail Dst 1233gc_bif2 Fail Live u$bif:erlang:bsr/2 S1 S2 Dst => \ 1234 i_bsr S1 S2 Fail Dst 1235 1236gc_bif2 Fail Live u$bif:erlang:band/2 S1 S2 Dst => \ 1237 i_band S1 S2 Fail Dst 1238 1239gc_bif2 Fail Live u$bif:erlang:bor/2 S1 S2 Dst => \ 1240 i_bor Fail S1 S2 Dst 1241 1242gc_bif2 Fail Live u$bif:erlang:bxor/2 S1 S2 Dst => \ 1243 i_bxor Fail S1 S2 Dst 1244 1245gc_bif1 Fail Live u$bif:erlang:bnot/1 Src Dst => \ 1246 i_bnot Fail Src Dst 1247 1248i_increment S W d 1249 1250i_plus s s j? d 1251i_minus s s j? d 1252 1253i_unary_minus s j? d 1254 1255i_times j? s s d 1256 1257i_m_div j? s s d 1258 1259i_rem_div s s j? d d 1260i_div_rem s s j? d d 1261i_int_div j? s s d 1262i_rem s s j? d 1263 1264i_bsl s s j? d 1265i_bsr s s j? d 1266 1267i_band s s j? d 1268i_bor j? s s d 1269i_bxor j? s s d 1270 1271i_bnot j? s d 1272 1273# 1274# Old guard BIFs that creates heap fragments are no longer allowed. 1275# 1276bif1 Fail u$bif:erlang:length/1 s d => too_old_compiler 1277bif1 Fail u$bif:erlang:size/1 s d => too_old_compiler 1278bif1 Fail u$bif:erlang:abs/1 s d => too_old_compiler 1279bif1 Fail u$bif:erlang:float/1 s d => too_old_compiler 1280bif1 Fail u$bif:erlang:round/1 s d => too_old_compiler 1281bif1 Fail u$bif:erlang:trunc/1 s d => too_old_compiler 1282 1283# 1284# Handle the length/1 guard BIF specially to make it trappable. 1285# 1286 1287gc_bif1 Fail=j Live u$bif:erlang:length/1 Src Dst => \ 1288 i_length_setup Fail Live Src | i_length Fail Live Dst 1289 1290i_length_setup j? t s 1291i_length j? t d 1292 1293# 1294# Guard BIFs. 1295# 1296gc_bif1 Fail Live Bif Src Dst => i_bif1 Src Fail Bif Dst 1297gc_bif2 Fail Live Bif S1 S2 Dst => i_bif2 S1 S2 Fail Bif Dst 1298gc_bif3 Fail Live Bif S1 S2 S3 Dst => i_bif3 S1 S2 S3 Fail Bif Dst 1299 1300# 1301# The following instruction is specially handled in beam_load.c 1302# to produce a user-friendly message if an unsupported guard BIF is 1303# encountered. 1304# 1305unsupported_guard_bif/3 1306unsupported_guard_bif A B C | never() => 1307 1308# 1309# R13B03 1310# 1311on_load 1312 1313# 1314# R14A. 1315# 1316# Superseded in OTP 24 by 'recv_marker_reserve' and friends. 1317# 1318 1319recv_mark f => i_recv_mark 1320i_recv_mark 1321 1322recv_set Fail | label Lbl | loop_rec Lf Reg => \ 1323 i_recv_set | label Lbl | loop_rec Lf Reg 1324i_recv_set 1325 1326# 1327# OTP 21. 1328# 1329 1330build_stacktrace 1331raw_raise 1332 1333# 1334# Specialized move instructions. Since they don't require a second 1335# instruction, we have intentionally placed them after any other 1336# transformation rules that starts with a move instruction in order to 1337# produce better code for the transformation engine. 1338# 1339 1340move n D=y => init D 1341 1342# 1343# OTP 24 1344# 1345 1346recv_marker_reserve S 1347recv_marker_bind S S 1348recv_marker_clear S 1349recv_marker_use S 1350