diff options
Diffstat (limited to 'erts/emulator/beam/jit/arm/generators.tab')
-rw-r--r-- | erts/emulator/beam/jit/arm/generators.tab | 141 |
1 files changed, 98 insertions, 43 deletions
diff --git a/erts/emulator/beam/jit/arm/generators.tab b/erts/emulator/beam/jit/arm/generators.tab index b6ec48c678..2ae1582d4b 100644 --- a/erts/emulator/beam/jit/arm/generators.tab +++ b/erts/emulator/beam/jit/arm/generators.tab @@ -2,7 +2,7 @@ // // %CopyrightBegin% // -// Copyright Ericsson AB 2020-2022. All Rights Reserved. +// Copyright Ericsson AB 2020-2023. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -19,47 +19,6 @@ // %CopyrightEnd% // -// Generate the fastest instruction to fetch an integer from a binary. -gen.get_integer2(Fail, Ms, Live, Size, Unit, Flags, Dst) { - BeamOp* op; - UWord bits; - - $NewBeamOp(S, op); - $NativeEndian(Flags); - - if (Size.type == TAG_i) { - if (!beam_load_safe_mul(Size.val, Unit.val, &bits)) { - $BeamOpNameArity(op, jump, 1); - op->a[0] = Fail; - - return op; - } else if (bits <= 1023) { - $BeamOpNameArity(op, i_bs_get_fixed_integer, 6); - op->a[0] = Ms; - op->a[1] = Fail; - op->a[2] = Live; - op->a[3].type = TAG_u; - op->a[3].val = Flags.val; - op->a[4].type = TAG_u; - op->a[4].val = bits; - op->a[5] = Dst; - - return op; - } - } - - $BeamOpNameArity(op, i_bs_get_integer, 6); - op->a[0] = Ms; - op->a[1] = Fail; - op->a[2] = Live; - op->a[3].type = TAG_u; - op->a[3].val = (Unit.val << 3) | Flags.val; - op->a[4] = Size; - op->a[5] = Dst; - - return op; -} - gen.select_tuple_arity(Src, Fail, Size, Rest) { BeamOp* op; BeamOpArg *tmp; @@ -330,7 +289,7 @@ gen.new_small_map_lit(Dst, Live, Size, Rest) { *dst++ = Rest[i + 1]; } - lit = beamfile_add_literal(&S->beam, keys); + lit = beamfile_add_literal(&S->beam, keys, 1); erts_free(ERTS_ALC_T_LOADER_TMP, tmp); op->a[0] = Dst; @@ -567,6 +526,28 @@ gen.create_bin(Fail, Alloc, Live, Unit, Dst, N, Segments) { Flags.val = flags; $NativeEndian(Flags); op->a[i+fixed_args+3] = Flags; + + /* + * Replace short string segments with integer segments. + * Integer segments can be combined with adjacent integer + * segments for better performance. + */ + if (op->a[i+fixed_args+0].val == am_string) { + Sint num_chars = op->a[i+fixed_args+5].val; + if (num_chars <= 4) { + Sint index = op->a[i+fixed_args+4].val; + const byte* s = S->beam.strings.data + index; + Uint num = 0; + op->a[i+fixed_args+0].val = am_integer; + op->a[i+fixed_args+2].val = 8; + op->a[i+fixed_args+5].val = num_chars; + while (num_chars-- > 0) { + num = num << 8 | *s++; + } + op->a[i+fixed_args+4].type = TAG_i; + op->a[i+fixed_args+4].val = num; + } + } } if (op->a[4].val == am_private_append && Alloc.val != 0) { @@ -584,3 +565,77 @@ gen.create_bin(Fail, Alloc, Live, Unit, Dst, N, Segments) { return op; } + +gen.bs_match(Fail, Ctx, N, List) { + BeamOp* op; + int fixed_args; + int i; + + /* + * If a BEAM file produced by a later version of Erlang/OTP + * is accidentally loaded into an earlier version, ensure + * that the loading fails (as opposed to crashing the runtime) + * if there are any unknown sub commands. + */ + i = 0; + while (i < N.val) { + BeamOpArg current = List[i++]; + + if (current.type != TAG_a) { + goto error; + } + + switch (current.val) { + case am_ensure_exactly: + case am_skip: + i += 1; + break; + case am_ensure_at_least: + i += 2; + break; + case am_get_tail: + case am_Eq: + i += 3; + break; + case am_binary: + case am_integer: + i += 5; + break; + default: { + error: + $NewBeamOp(S, op); + $BeamOpNameArity(op, bad_bs_match, 1); + op->a[0] = current; + return op; + } + } + } + + /* + * Make sure that we don't attempt to pass any overflow tags to the JIT. + */ + + $NewBeamOp(S, op); + $BeamOpNameArity(op, i_bs_match, 2); + fixed_args = op->arity; + $BeamOpArity(op, (N.val + fixed_args)); + + op->a[0] = Fail; + op->a[1] = Ctx; + + for (i = 0; i < N.val; i++) { + BeamOpArg current; + + current = List[i]; + if (current.type == TAG_o) { + /* An overflow tag (in ensure_at_least or ensure_exactly) + * means that the match will always fail. */ + $BeamOpNameArity(op, jump, 1); + op->a[0] = Fail; + return op; + } + op->a[i+fixed_args] = current; + } + + return op; +} |