diff options
Diffstat (limited to 'erts/emulator/beam/jit/x86/generators.tab')
-rw-r--r-- | erts/emulator/beam/jit/x86/generators.tab | 175 |
1 files changed, 98 insertions, 77 deletions
diff --git a/erts/emulator/beam/jit/x86/generators.tab b/erts/emulator/beam/jit/x86/generators.tab index 4b0b2ad043..007344d17d 100644 --- a/erts/emulator/beam/jit/x86/generators.tab +++ b/erts/emulator/beam/jit/x86/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,60 +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; - } else if (bits == 8) { - $BeamOpNameArity(op, i_bs_get_integer_8, 4); - op->a[0] = Ms; - op->a[1] = Flags; - op->a[2] = Fail; - op->a[3] = Dst; - } else if (bits == 16) { - $BeamOpNameArity(op, i_bs_get_integer_16, 4); - op->a[0] = Ms; - op->a[1] = Flags; - op->a[2] = Fail; - op->a[3] = Dst; - } else if (bits == 32) { - $BeamOpNameArity(op, i_bs_get_integer_32, 4); - op->a[0] = Ms; - op->a[1] = Flags; - op->a[2] = Fail; - op->a[3] = Dst; - } else if (bits == 64) { - $BeamOpNameArity(op, i_bs_get_integer_64, 5); - op->a[0] = Ms; - op->a[1] = Flags; - op->a[2] = Fail; - op->a[3] = Live; - op->a[4] = Dst; - } else { - goto generic; - } - } else { - generic: - $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; - } - return op; -} - gen.select_tuple_arity(Src, Fail, Size, Rest) { BeamOp* op; BeamOpArg *tmp; @@ -413,7 +359,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; @@ -487,27 +433,6 @@ gen.combine_conses(Len, Dst, Hd) { return cons; } -gen.is_eq_exact_literal(Fail, R, C) { - BeamOp* op; - Eterm literal; - Uint tag_test; - - ASSERT(C.type == TAG_q); - literal = beamfile_get_literal(&S->beam, C.val); - ASSERT(is_boxed(literal) || is_list(literal)); - tag_test = _TAG_PRIMARY_MASK - (literal & _TAG_PRIMARY_MASK); - - $NewBeamOp(S, op); - $BeamOpNameArity(op, i_is_eq_exact_literal, 4); - op->a[0] = Fail; - op->a[1] = R; - op->a[2] = C; - op->a[3].type = TAG_u; - op->a[3].val = tag_test; - - return op; -} - gen.allocate_heap_zero(Ns, Nh, Live) { BeamOp* alloc; BeamOp* init; @@ -635,6 +560,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) { @@ -652,3 +599,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; +} |