File 1125-Simplify-updating-a-single-element-of-a-map.patch of Package erlang
From 2b227d7149ab81f90a482853a7842ae8f1cde7ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Mon, 4 Sep 2023 06:14:03 +0200
Subject: [PATCH 05/25] Simplify updating a single element of a map
---
erts/emulator/beam/jit/arm/beam_asm.hpp | 30 +++++
.../beam/jit/arm/beam_asm_global.hpp.pl | 6 +-
erts/emulator/beam/jit/arm/instr_map.cpp | 101 +++++++++++++----
.../beam/jit/x86/beam_asm_global.hpp.pl | 2 +
erts/emulator/beam/jit/x86/instr_map.cpp | 104 ++++++++++++++----
5 files changed, 201 insertions(+), 42 deletions(-)
diff --git a/erts/emulator/beam/jit/arm/beam_asm.hpp b/erts/emulator/beam/jit/arm/beam_asm.hpp
index 38f1c6875f..c51edb512f 100644
--- a/erts/emulator/beam/jit/arm/beam_asm.hpp
+++ b/erts/emulator/beam/jit/arm/beam_asm.hpp
@@ -1440,6 +1440,36 @@ protected:
return Variable<arm::VecD>(tmp);
}
+ void emit_load_args(const ArgSource &Src1,
+ arm::Gp src1_default,
+ const ArgSource &Src2,
+ arm::Gp src2_default,
+ const ArgSource &Src3,
+ arm::Gp src3_default) {
+ if (isRegisterBacked(Src1) || !Src1.isRegister()) {
+ auto src1 = load_source(Src1, src1_default);
+ auto [src2, src3] =
+ load_sources(Src2, src2_default, Src3, src3_default);
+ mov_var(src1_default, src1);
+ mov_var(src2_default, src2);
+ mov_var(src3_default, src3);
+ } else if (isRegisterBacked(Src2) || !Src2.isRegister()) {
+ auto [src1, src3] =
+ load_sources(Src1, src1_default, Src3, src3_default);
+ auto src2 = load_source(Src2, src2_default);
+ mov_var(src1_default, src1);
+ mov_var(src2_default, src2);
+ mov_var(src3_default, src3);
+ } else {
+ auto [src1, src2] =
+ load_sources(Src1, src1_default, Src2, src2_default);
+ auto src3 = load_source(Src3, src3_default);
+ mov_var(src1_default, src1);
+ mov_var(src2_default, src2);
+ mov_var(src3_default, src3);
+ }
+ }
+
template<typename Reg>
void mov_var(const Variable<Reg> &to, const Variable<Reg> &from) {
mov_var(to.reg, from);
diff --git a/erts/emulator/beam/jit/arm/beam_asm_global.hpp.pl b/erts/emulator/beam/jit/arm/beam_asm_global.hpp.pl
index 93b239ddbd..0cb95c5ce3 100644
--- a/erts/emulator/beam/jit/arm/beam_asm_global.hpp.pl
+++ b/erts/emulator/beam/jit/arm/beam_asm_global.hpp.pl
@@ -103,17 +103,19 @@ my @beam_global_funcs = qw(
mul_body_shared
mul_guard_shared
new_map_shared
- update_map_assoc_shared
- unloaded_fun
plus_body_shared
process_exit
process_main
raise_exception
raise_exception_shared
store_unaligned
+ unloaded_fun
unary_minus_body_shared
+ update_map_assoc_shared
+ update_map_single_assoc_shared
update_map_exact_guard_shared
update_map_exact_body_shared
+ update_map_single_exact_body_shared
);
diff --git a/erts/emulator/beam/jit/arm/instr_map.cpp b/erts/emulator/beam/jit/arm/instr_map.cpp
index daecdb80ef..129c29d5b2 100644
--- a/erts/emulator/beam/jit/arm/instr_map.cpp
+++ b/erts/emulator/beam/jit/arm/instr_map.cpp
@@ -545,23 +545,44 @@ void BeamGlobalAssembler::emit_update_map_assoc_shared() {
a.ret(a64::x30);
}
+/* ARG2 = key
+ * ARG3 = value
+ * ARG4 = map
+ */
+void BeamGlobalAssembler::emit_update_map_single_assoc_shared() {
+ emit_enter_runtime_frame();
+ emit_enter_runtime<Update::eHeapAlloc>();
+
+ a.mov(ARG1, c_p);
+ runtime_call<4>(erts_maps_put);
+
+ emit_leave_runtime<Update::eHeapAlloc>();
+ emit_leave_runtime_frame();
+
+ a.ret(a64::x30);
+}
+
void BeamModuleAssembler::emit_update_map_assoc(const ArgSource &Src,
const ArgRegister &Dst,
const ArgWord &Live,
const ArgWord &Size,
const Span<ArgVal> &args) {
- auto src_reg = load_source(Src, TMP1);
-
ASSERT(Size.get() == args.size());
- embed_vararg_rodata(args, ARG5);
+ if (args.size() == 2) {
+ emit_load_args(args[0], ARG2, args[1], ARG3, Src, ARG4);
+ fragment_call(ga->get_update_map_single_assoc_shared());
+ } else {
+ auto src = load_source(Src, TMP1);
- mov_arg(ArgXRegister(Live.get()), src_reg.reg);
- mov_arg(ARG3, Live);
- mov_imm(ARG4, args.size());
+ embed_vararg_rodata(args, ARG5);
- fragment_call(ga->get_update_map_assoc_shared());
+ mov_arg(ArgXRegister(Live.get()), src.reg);
+ mov_arg(ARG3, Live);
+ mov_imm(ARG4, args.size());
+ fragment_call(ga->get_update_map_assoc_shared());
+ }
mov_arg(Dst, ARG1);
}
@@ -612,29 +633,67 @@ void BeamGlobalAssembler::emit_update_map_exact_body_shared() {
}
}
+/* ARG2 = key
+ * ARG3 = value
+ * ARG4 = map
+ *
+ * Does not return on error. */
+void BeamGlobalAssembler::emit_update_map_single_exact_body_shared() {
+ Label error = a.newLabel();
+
+ a.str(ARG2, TMP_MEM2q);
+
+ emit_enter_runtime_frame();
+ emit_enter_runtime<Update::eHeapAlloc>();
+
+ a.mov(ARG1, c_p);
+ lea(ARG5, TMP_MEM1q);
+ runtime_call<5>(erts_maps_update);
+
+ emit_leave_runtime<Update::eHeapAlloc>();
+ emit_leave_runtime_frame();
+
+ a.cbz(ARG1.w(), error);
+
+ a.ldr(ARG1, TMP_MEM1q);
+ a.ret(a64::x30);
+
+ a.bind(error);
+ {
+ a.ldr(TMP2, TMP_MEM2q);
+ mov_imm(TMP1, BADKEY);
+ ERTS_CT_ASSERT_FIELD_PAIR(Process, freason, fvalue);
+ a.stp(TMP1, TMP2, arm::Mem(c_p, offsetof(Process, freason)));
+ mov_imm(ARG4, 0);
+ a.b(labels[raise_exception]);
+ }
+}
+
void BeamModuleAssembler::emit_update_map_exact(const ArgSource &Src,
const ArgLabel &Fail,
const ArgRegister &Dst,
const ArgWord &Live,
const ArgWord &Size,
const Span<ArgVal> &args) {
- auto src_reg = load_source(Src, TMP1);
-
ASSERT(Size.get() == args.size());
- embed_vararg_rodata(args, ARG5);
-
- /* We _KNOW_ Src is a map */
-
- mov_arg(ArgXRegister(Live.get()), src_reg.reg);
- mov_arg(ARG3, Live);
- mov_imm(ARG4, args.size());
-
- if (Fail.get() != 0) {
- fragment_call(ga->get_update_map_exact_guard_shared());
- emit_branch_if_not_value(ARG1, resolve_beam_label(Fail, dispUnknown));
+ if (args.size() == 2 && Fail.get() == 0) {
+ emit_load_args(args[0], ARG2, args[1], ARG3, Src, ARG4);
+ fragment_call(ga->get_update_map_single_exact_body_shared());
} else {
- fragment_call(ga->get_update_map_exact_body_shared());
+ auto src = load_source(Src, ARG4);
+ embed_vararg_rodata(args, ARG5);
+ mov_arg(ArgXRegister(Live.get()), src.reg);
+ mov_arg(ARG3, Live);
+ mov_imm(ARG4, args.size());
+
+ if (Fail.get() != 0) {
+ fragment_call(ga->get_update_map_exact_guard_shared());
+ emit_branch_if_not_value(ARG1,
+ resolve_beam_label(Fail, dispUnknown));
+ } else {
+ fragment_call(ga->get_update_map_exact_body_shared());
+ }
}
mov_arg(Dst, ARG1);
diff --git a/erts/emulator/beam/jit/x86/beam_asm_global.hpp.pl b/erts/emulator/beam/jit/x86/beam_asm_global.hpp.pl
index 9782bbb226..e6f8a53219 100755
--- a/erts/emulator/beam/jit/x86/beam_asm_global.hpp.pl
+++ b/erts/emulator/beam/jit/x86/beam_asm_global.hpp.pl
@@ -108,6 +108,8 @@ my @beam_global_funcs = qw(
update_map_assoc_shared
update_map_exact_guard_shared
update_map_exact_body_shared
+ update_map_single_assoc_shared
+ update_map_single_exact_body_shared
);
# Labels exported from within process_main
diff --git a/erts/emulator/beam/jit/x86/instr_map.cpp b/erts/emulator/beam/jit/x86/instr_map.cpp
index 18eb9eb50a..c386208b63 100644
--- a/erts/emulator/beam/jit/x86/instr_map.cpp
+++ b/erts/emulator/beam/jit/x86/instr_map.cpp
@@ -574,21 +574,45 @@ void BeamGlobalAssembler::emit_update_map_assoc_shared() {
a.ret();
}
+/* ARG2 = key
+ * ARG3 = value
+ * ARG4 = map
+ */
+void BeamGlobalAssembler::emit_update_map_single_assoc_shared() {
+ emit_enter_frame();
+ emit_enter_runtime<Update::eHeapAlloc>();
+
+ a.mov(ARG1, c_p);
+ runtime_call<4>(erts_maps_put);
+
+ emit_leave_runtime<Update::eHeapAlloc>();
+ emit_leave_frame();
+
+ a.ret();
+}
+
void BeamModuleAssembler::emit_update_map_assoc(const ArgSource &Src,
const ArgRegister &Dst,
const ArgWord &Live,
const ArgWord &Size,
const Span<ArgVal> &args) {
- Label data = embed_vararg_rodata(args, CP_SIZE);
-
ASSERT(Size.get() == args.size());
- mov_arg(getXRef(Live.get()), Src);
+ if (args.size() == 2) {
+ mov_arg(ARG2, args[0]);
+ mov_arg(ARG3, args[1]);
+ mov_arg(ARG4, Src);
+ safe_fragment_call(ga->get_update_map_single_assoc_shared());
+ } else {
+ Label data = embed_vararg_rodata(args, CP_SIZE);
- mov_imm(ARG3, Live.get());
- mov_imm(ARG4, args.size());
- a.lea(ARG5, x86::qword_ptr(data));
- fragment_call(ga->get_update_map_assoc_shared());
+ mov_arg(getXRef(Live.get()), Src);
+
+ mov_imm(ARG3, Live.get());
+ mov_imm(ARG4, args.size());
+ a.lea(ARG5, x86::qword_ptr(data));
+ fragment_call(ga->get_update_map_assoc_shared());
+ }
mov_arg(Dst, RET);
}
@@ -639,28 +663,70 @@ void BeamGlobalAssembler::emit_update_map_exact_body_shared() {
}
}
+/* ARG2 = key
+ * ARG3 = value
+ * ARG4 = map
+ *
+ * Does not return on error. */
+void BeamGlobalAssembler::emit_update_map_single_exact_body_shared() {
+ Label error = a.newLabel();
+
+ a.mov(TMP_MEM2q, ARG2);
+
+ emit_enter_frame();
+ emit_enter_runtime<Update::eHeapAlloc>();
+
+ a.mov(ARG1, c_p);
+ a.lea(ARG5, TMP_MEM1q);
+ runtime_call<5>(erts_maps_update);
+
+ emit_leave_runtime<Update::eHeapAlloc>();
+ emit_leave_frame();
+
+ a.test(RETd, RETd);
+ a.short_().je(error);
+
+ a.mov(RET, TMP_MEM1q);
+ a.ret();
+
+ a.bind(error);
+ {
+ a.mov(RET, TMP_MEM2q);
+ a.mov(x86::qword_ptr(c_p, offsetof(Process, freason)), imm(BADKEY));
+ a.mov(x86::qword_ptr(c_p, offsetof(Process, fvalue)), RET);
+ mov_imm(ARG4, 0);
+ a.jmp(labels[raise_exception]);
+ }
+}
+
void BeamModuleAssembler::emit_update_map_exact(const ArgSource &Src,
const ArgLabel &Fail,
const ArgRegister &Dst,
const ArgWord &Live,
const ArgWord &Size,
const Span<ArgVal> &args) {
- Label data = embed_vararg_rodata(args, CP_SIZE);
-
ASSERT(Size.get() == args.size());
- /* We _KNOW_ Src is a map */
- mov_arg(getXRef(Live.get()), Src);
+ if (args.size() == 2 && Fail.get() == 0) {
+ mov_arg(ARG2, args[0]);
+ mov_arg(ARG3, args[1]);
+ mov_arg(ARG4, Src);
+ fragment_call(ga->get_update_map_single_exact_body_shared());
+ } else {
+ Label data = embed_vararg_rodata(args, CP_SIZE);
- mov_imm(ARG3, Live.get());
- mov_imm(ARG4, args.size());
- a.lea(ARG5, x86::qword_ptr(data));
+ mov_arg(getXRef(Live.get()), Src);
- if (Fail.get() != 0) {
- fragment_call(ga->get_update_map_exact_guard_shared());
- a.je(resolve_beam_label(Fail));
- } else {
- fragment_call(ga->get_update_map_exact_body_shared());
+ mov_imm(ARG3, Live.get());
+ mov_imm(ARG4, args.size());
+ a.lea(ARG5, x86::qword_ptr(data));
+
+ if (Fail.get() != 0) {
+ fragment_call(ga->get_update_map_exact_guard_shared());
+ a.je(resolve_beam_label(Fail));
+ } else {
+ fragment_call(ga->get_update_map_exact_body_shared());
+ }
}
mov_arg(Dst, RET);
--
2.35.3