Skip to content

Commit 085efcf

Browse files
committed
Compile literal binary patterns in the loader
1 parent 50d69f7 commit 085efcf

15 files changed

Lines changed: 265 additions & 10 deletions

File tree

erts/emulator/beam/beam_transform_helpers.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
#endif
2626

2727
#include "sys.h"
28+
#include "global.h"
2829
#include "beam_load.h"
30+
#include "erl_bif_unique.h"
2931
#include "erl_map.h"
3032
#include "beam_transform_helpers.h"
3133

@@ -138,6 +140,29 @@ beam_load_sort_select_vals(BeamOpArg* base, size_t n)
138140
(int (*)(const void *, const void *)) oparg_compare);
139141
}
140142

143+
int
144+
beam_load_compile_binary_pattern(LoaderState *stp, BeamOpArg pattern)
145+
{
146+
Eterm heap[ERTS_MAGIC_REF_THING_SIZE + 3];
147+
Binary *bin;
148+
Eterm compiled, magic_ref, source, tag;
149+
Eterm *hp = heap;
150+
ErlOffHeap off_heap;
151+
152+
source = beamfile_get_literal(&stp->beam, pattern.val);
153+
if (!erts_binary_compile_pattern(source, &tag, &bin)) {
154+
return 0;
155+
}
156+
157+
ERTS_INIT_OFF_HEAP(&off_heap);
158+
magic_ref = erts_mk_magic_ref(&hp, &off_heap, bin);
159+
compiled = TUPLE2(hp, tag, magic_ref);
160+
161+
stp->loaded_binary_pattern = beamfile_add_literal(&stp->beam, compiled, 0);
162+
erts_cleanup_offheap(&off_heap);
163+
return 1;
164+
}
165+
141166
static int
142167
oparg_compare(BeamOpArg* a, BeamOpArg* b)
143168
{

erts/emulator/beam/beam_transform_helpers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@ int beam_load_safe_mul(UWord a, UWord b, UWord* resp);
2727
int beam_load_map_key_sort(LoaderState* stp, BeamOpArg Size, BeamOpArg* Rest);
2828
Eterm beam_load_get_term(LoaderState* stp, BeamOpArg Key);
2929
void beam_load_sort_select_vals(BeamOpArg* base, size_t n);
30+
int beam_load_compile_binary_pattern(LoaderState *stp, BeamOpArg pattern);
3031
#endif

erts/emulator/beam/emu/load.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ struct LoaderState_ {
147147
/* Translates lambda indexes to their canonical literal, if any. */
148148
SWord *lambda_literals;
149149

150+
/* Dynamic literal produced by the current binary pattern transform. */
151+
SWord loaded_binary_pattern;
152+
150153
int otp_20_or_higher;
151154

152155
Uint last_func_start;

erts/emulator/beam/emu/ops.tab

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,23 @@ call_ext_last u==0 u$func:os:perf_counter/0 D =>
904904
call_ext_only u==0 u$func:os:perf_counter/0 =>
905905
i_perf_counter | return
906906

907+
# Compile literal binary search patterns while loading. Invalid patterns decline
908+
# these transforms and retain their original runtime error behavior.
909+
#
910+
911+
move Pattern=q X0=x==0 |
912+
call_ext _Ar=u _Func=u$bif:binary:compile_pattern/1 |
913+
load_binary_pattern(Pattern) =>
914+
loaded_binary_pattern(X0)
915+
move Pattern=q X0=x==0 |
916+
call_ext_last _Ar=u _Func=u$bif:binary:compile_pattern/1 D |
917+
load_binary_pattern(Pattern) =>
918+
loaded_binary_pattern_last(X0, D)
919+
move Pattern=q X0=x==0 |
920+
call_ext_only _Ar=u _Func=u$bif:binary:compile_pattern/1 |
921+
load_binary_pattern(Pattern) =>
922+
loaded_binary_pattern_only(X0)
923+
907924
#
908925
# BIFs like process_info/1,2 require up-to-date information about the current
909926
# emulator state, which the ordinary call_light_bif instruction doesn't save.

erts/emulator/beam/erl_bif_binary.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,18 +1100,23 @@ static int do_binary_match_compile(Eterm argument, Eterm *tag, Binary **binp)
11001100
return -1;
11011101
}
11021102

1103+
int erts_binary_compile_pattern(Eterm argument, Eterm *tag, Binary **binp)
1104+
{
1105+
return do_binary_match_compile(argument, tag, binp) == 0;
1106+
}
1107+
11031108
BIF_RETTYPE binary_compile_pattern_1(BIF_ALIST_1)
11041109
{
11051110
Binary *bin;
1106-
Eterm tag, ret;
1111+
Eterm magic_ref, ret, tag;
11071112
Eterm *hp;
11081113

1109-
if (do_binary_match_compile(BIF_ARG_1,&tag,&bin)) {
1110-
BIF_ERROR(BIF_P,BADARG);
1114+
if (!erts_binary_compile_pattern(BIF_ARG_1, &tag, &bin)) {
1115+
BIF_ERROR(BIF_P, BADARG);
11111116
}
1112-
hp = HAlloc(BIF_P, ERTS_MAGIC_REF_THING_SIZE+3);
1113-
ret = erts_mk_magic_ref(&hp, &MSO(BIF_P), bin);
1114-
ret = TUPLE2(hp, tag, ret);
1117+
hp = HAlloc(BIF_P, ERTS_MAGIC_REF_THING_SIZE + 3);
1118+
magic_ref = erts_mk_magic_ref(&hp, &MSO(BIF_P), bin);
1119+
ret = TUPLE2(hp, tag, magic_ref);
11151120
BIF_RET(ret);
11161121
}
11171122

erts/emulator/beam/generators.tab

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,47 @@ gen.get_float2(Fail, Ms, Live, Size, Unit, Flags, Dst) {
7070
return op;
7171
}
7272

73+
LoadedBinaryPatternMove(Op, Dst) {
74+
$BeamOpNameArity($Op, move, 2);
75+
($Op)->a[0].type = TAG_q;
76+
($Op)->a[0].val = S->loaded_binary_pattern;
77+
($Op)->a[1] = $Dst;
78+
}
79+
80+
gen.loaded_binary_pattern(Dst) {
81+
BeamOp *move;
82+
$NewBeamOp(S, move);
83+
84+
$LoadedBinaryPatternMove(move, Dst);
85+
return move;
86+
}
87+
88+
gen.loaded_binary_pattern_last(Dst, Deallocate) {
89+
BeamOp *move, *deallocate, *ret;
90+
$NewBeamOp(S, move);
91+
$NewBeamOp(S, deallocate);
92+
$NewBeamOp(S, ret);
93+
94+
$LoadedBinaryPatternMove(move, Dst);
95+
$BeamOpNameArity(deallocate, deallocate, 1);
96+
deallocate->a[0] = Deallocate;
97+
$BeamOpNameArity(ret, return, 0);
98+
move->next = deallocate;
99+
deallocate->next = ret;
100+
return move;
101+
}
102+
103+
gen.loaded_binary_pattern_only(Dst) {
104+
BeamOp *move, *ret;
105+
$NewBeamOp(S, move);
106+
$NewBeamOp(S, ret);
107+
108+
$LoadedBinaryPatternMove(move, Dst);
109+
$BeamOpNameArity(ret, return, 0);
110+
move->next = ret;
111+
return move;
112+
}
113+
73114
gen.get_utf16(Fail, Ms, Flags, Dst) {
74115
BeamOp* op;
75116
$NewBeamOp(S, op);

erts/emulator/beam/global.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1450,6 +1450,7 @@ Sint erts_re_set_loop_limit(Sint limit);
14501450
/* erl_bif_binary.c */
14511451
void erts_init_bif_binary(void);
14521452
Sint erts_binary_set_loop_limit(Sint limit);
1453+
int erts_binary_compile_pattern(Eterm argument, Eterm *tag, Binary **binp);
14531454

14541455
/* erl_bif_persistent.c */
14551456
Eterm erts_persistent_term_get(Eterm key);

erts/emulator/beam/jit/arm/ops.tab

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ move S X0=x==0 | line _Loc | call_last Ar Func D =>
8282
move S X0=x==0 | line _Loc | call_only Ar Func =>
8383
move S X0 | call_only Ar Func
8484

85+
# Move literal call arguments past line instructions so they can participate
86+
# in load-time call transformations.
87+
move S=c X0=x==0 | line Loc => line Loc | move S X0
88+
8589
# The line number in int_func_start/5 can be NIL.
8690
func_line n => empty_func_line
8791

@@ -395,6 +399,23 @@ move_two_trim y d y d t
395399

396400
move_trim s d t
397401

402+
# Compile literal binary search patterns while loading. Invalid patterns decline
403+
# these transforms and retain their original runtime error behavior.
404+
#
405+
406+
move Pattern=q X0=x==0 |
407+
call_ext _Ar=u _Func=u$bif:binary:compile_pattern/1 |
408+
load_binary_pattern(Pattern) =>
409+
loaded_binary_pattern(X0)
410+
move Pattern=q X0=x==0 |
411+
call_ext_last _Ar=u _Func=u$bif:binary:compile_pattern/1 D |
412+
load_binary_pattern(Pattern) =>
413+
loaded_binary_pattern_last(X0, D)
414+
move Pattern=q X0=x==0 |
415+
call_ext_only _Ar=u _Func=u$bif:binary:compile_pattern/1 |
416+
load_binary_pattern(Pattern) =>
417+
loaded_binary_pattern_only(X0)
418+
398419
move Src Dst => i_move Src Dst
399420

400421
i_move s d

erts/emulator/beam/jit/load.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ struct LoaderState_ {
9595
/* Translates lambda indexes to their canonical literal, if any. */
9696
SWord *lambda_literals;
9797

98+
/* Dynamic literal produced by the current binary pattern transform. */
99+
SWord loaded_binary_pattern;
100+
98101
void *ba; /* Assembler used to create x86/AArch64 assembly */
99102

100103
const void *executable_region; /* Native module after codegen */

erts/emulator/beam/jit/x86/ops.tab

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ move S X0=x==0 | line _Loc | call_last Ar Func D =>
8282
move S X0=x==0 | line _Loc | call_only Ar Func =>
8383
move S X0 | call_only Ar Func
8484

85+
# Move literal call arguments past line instructions so they can participate
86+
# in load-time call transformations.
87+
move S=c X0=x==0 | line Loc => line Loc | move S X0
88+
8589
# The line number in int_func_start/5 can be NIL.
8690
func_line n => empty_func_line
8791

@@ -363,6 +367,23 @@ move S1=d D1=d | move S2=d D2=d | consecutive_words(S2, D1, S1, D2) =>
363367
move S1=d D1=d | move S2=d D2=d | consecutive_words(S2, D2, S1, D1) =>
364368
move_two_words S2 D2 S1 D1
365369

370+
# Compile literal binary search patterns while loading. Invalid patterns decline
371+
# these transforms and retain their original runtime error behavior.
372+
#
373+
374+
move Pattern=q X0=x==0 |
375+
call_ext _Ar=u _Func=u$bif:binary:compile_pattern/1 |
376+
load_binary_pattern(Pattern) =>
377+
loaded_binary_pattern(X0)
378+
move Pattern=q X0=x==0 |
379+
call_ext_last _Ar=u _Func=u$bif:binary:compile_pattern/1 D |
380+
load_binary_pattern(Pattern) =>
381+
loaded_binary_pattern_last(X0, D)
382+
move Pattern=q X0=x==0 |
383+
call_ext_only _Ar=u _Func=u$bif:binary:compile_pattern/1 |
384+
load_binary_pattern(Pattern) =>
385+
loaded_binary_pattern_only(X0)
386+
366387
move Src Dst => i_move Src Dst
367388

368389
#

0 commit comments

Comments
 (0)