diff options
| author | Paul Eggert | 2017-09-26 16:31:57 -0700 |
|---|---|---|
| committer | Paul Eggert | 2017-09-26 16:36:43 -0700 |
| commit | 0e82fa34163dba21121e3a9cffa7f896c81c4d93 (patch) | |
| tree | 16c728aa616dae256d429060e257313dcfe4dbde /src | |
| parent | 98a37e60142340b9c2b4e6b17c373f4ae6a2d8b4 (diff) | |
| download | emacs-0e82fa34163dba21121e3a9cffa7f896c81c4d93.tar.gz emacs-0e82fa34163dba21121e3a9cffa7f896c81c4d93.zip | |
Avoid some unnecessary copying in Fformat etc.
This patch is just for performance; it should not affect behavior.
On my platform, it made the microbenchmark (format "%S" load-path)
run about 45% faster. It should also speed up calls like (message
"%s" STRING).
* src/callint.c (Fcall_interactively):
* src/dbusbind.c (XD_OBJECT_TO_STRING):
* src/editfns.c (Fmessage, Fmessage_box):
* src/xdisp.c (vadd_to_log, Ftrace_to_stderr):
Use styled_format instead of Fformat or Fformat_message,
to avoid unnecessary copying.
* src/editfns.c (styled_format): New arg NEW_RESULT.
All uses changed. Reuse an input string if it has the
right value and if !NEW_RESULT.
* src/lisp.h (style_format): New decl.
Diffstat (limited to 'src')
| -rw-r--r-- | src/callint.c | 7 | ||||
| -rw-r--r-- | src/dbusbind.c | 3 | ||||
| -rw-r--r-- | src/editfns.c | 47 | ||||
| -rw-r--r-- | src/lisp.h | 1 | ||||
| -rw-r--r-- | src/xdisp.c | 4 |
5 files changed, 44 insertions, 18 deletions
diff --git a/src/callint.c b/src/callint.c index 105ec071d07..469205cc380 100644 --- a/src/callint.c +++ b/src/callint.c | |||
| @@ -272,7 +272,7 @@ invoke it. If KEYS is omitted or nil, the return value of | |||
| 272 | { | 272 | { |
| 273 | /* `args' will contain the array of arguments to pass to the function. | 273 | /* `args' will contain the array of arguments to pass to the function. |
| 274 | `visargs' will contain the same list but in a nicer form, so that if we | 274 | `visargs' will contain the same list but in a nicer form, so that if we |
| 275 | pass it to `Fformat_message' it will be understandable to a human. */ | 275 | pass it to styled_format it will be understandable to a human. */ |
| 276 | Lisp_Object *args, *visargs; | 276 | Lisp_Object *args, *visargs; |
| 277 | Lisp_Object specs; | 277 | Lisp_Object specs; |
| 278 | Lisp_Object filter_specs; | 278 | Lisp_Object filter_specs; |
| @@ -502,10 +502,7 @@ invoke it. If KEYS is omitted or nil, the return value of | |||
| 502 | for (i = 2; *tem; i++) | 502 | for (i = 2; *tem; i++) |
| 503 | { | 503 | { |
| 504 | visargs[1] = make_string (tem + 1, strcspn (tem + 1, "\n")); | 504 | visargs[1] = make_string (tem + 1, strcspn (tem + 1, "\n")); |
| 505 | if (strchr (SSDATA (visargs[1]), '%')) | 505 | callint_message = styled_format (i - 1, visargs + 1, true, false); |
| 506 | callint_message = Fformat_message (i - 1, visargs + 1); | ||
| 507 | else | ||
| 508 | callint_message = visargs[1]; | ||
| 509 | 506 | ||
| 510 | switch (*tem) | 507 | switch (*tem) |
| 511 | { | 508 | { |
diff --git a/src/dbusbind.c b/src/dbusbind.c index 4a7068416fe..789aa008611 100644 --- a/src/dbusbind.c +++ b/src/dbusbind.c | |||
| @@ -237,7 +237,8 @@ static char * | |||
| 237 | XD_OBJECT_TO_STRING (Lisp_Object object) | 237 | XD_OBJECT_TO_STRING (Lisp_Object object) |
| 238 | { | 238 | { |
| 239 | AUTO_STRING (format, "%s"); | 239 | AUTO_STRING (format, "%s"); |
| 240 | return SSDATA (CALLN (Fformat, format, object)); | 240 | Lisp_Object args[] = { format, object }; |
| 241 | return SSDATA (styled_format (ARRAYELTS (args), args, false, false)); | ||
| 241 | } | 242 | } |
| 242 | 243 | ||
| 243 | #define XD_DBUS_VALIDATE_BUS_ADDRESS(bus) \ | 244 | #define XD_DBUS_VALIDATE_BUS_ADDRESS(bus) \ |
diff --git a/src/editfns.c b/src/editfns.c index 2f8b075817a..ef0374199cc 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -74,7 +74,6 @@ static Lisp_Object format_time_string (char const *, ptrdiff_t, struct timespec, | |||
| 74 | static long int tm_gmtoff (struct tm *); | 74 | static long int tm_gmtoff (struct tm *); |
| 75 | static int tm_diff (struct tm *, struct tm *); | 75 | static int tm_diff (struct tm *, struct tm *); |
| 76 | static void update_buffer_properties (ptrdiff_t, ptrdiff_t); | 76 | static void update_buffer_properties (ptrdiff_t, ptrdiff_t); |
| 77 | static Lisp_Object styled_format (ptrdiff_t, Lisp_Object *, bool); | ||
| 78 | 77 | ||
| 79 | #ifndef HAVE_TM_GMTOFF | 78 | #ifndef HAVE_TM_GMTOFF |
| 80 | # define HAVE_TM_GMTOFF false | 79 | # define HAVE_TM_GMTOFF false |
| @@ -3959,7 +3958,7 @@ usage: (message FORMAT-STRING &rest ARGS) */) | |||
| 3959 | } | 3958 | } |
| 3960 | else | 3959 | else |
| 3961 | { | 3960 | { |
| 3962 | Lisp_Object val = Fformat_message (nargs, args); | 3961 | Lisp_Object val = styled_format (nargs, args, true, false); |
| 3963 | message3 (val); | 3962 | message3 (val); |
| 3964 | return val; | 3963 | return val; |
| 3965 | } | 3964 | } |
| @@ -3985,7 +3984,7 @@ usage: (message-box FORMAT-STRING &rest ARGS) */) | |||
| 3985 | } | 3984 | } |
| 3986 | else | 3985 | else |
| 3987 | { | 3986 | { |
| 3988 | Lisp_Object val = Fformat_message (nargs, args); | 3987 | Lisp_Object val = styled_format (nargs, args, true, false); |
| 3989 | Lisp_Object pane, menu; | 3988 | Lisp_Object pane, menu; |
| 3990 | 3989 | ||
| 3991 | pane = list1 (Fcons (build_string ("OK"), Qt)); | 3990 | pane = list1 (Fcons (build_string ("OK"), Qt)); |
| @@ -4141,7 +4140,7 @@ produced text. | |||
| 4141 | usage: (format STRING &rest OBJECTS) */) | 4140 | usage: (format STRING &rest OBJECTS) */) |
| 4142 | (ptrdiff_t nargs, Lisp_Object *args) | 4141 | (ptrdiff_t nargs, Lisp_Object *args) |
| 4143 | { | 4142 | { |
| 4144 | return styled_format (nargs, args, false); | 4143 | return styled_format (nargs, args, false, true); |
| 4145 | } | 4144 | } |
| 4146 | 4145 | ||
| 4147 | DEFUN ("format-message", Fformat_message, Sformat_message, 1, MANY, 0, | 4146 | DEFUN ("format-message", Fformat_message, Sformat_message, 1, MANY, 0, |
| @@ -4157,13 +4156,16 @@ and right quote replacement characters are specified by | |||
| 4157 | usage: (format-message STRING &rest OBJECTS) */) | 4156 | usage: (format-message STRING &rest OBJECTS) */) |
| 4158 | (ptrdiff_t nargs, Lisp_Object *args) | 4157 | (ptrdiff_t nargs, Lisp_Object *args) |
| 4159 | { | 4158 | { |
| 4160 | return styled_format (nargs, args, true); | 4159 | return styled_format (nargs, args, true, true); |
| 4161 | } | 4160 | } |
| 4162 | 4161 | ||
| 4163 | /* Implement ‘format-message’ if MESSAGE is true, ‘format’ otherwise. */ | 4162 | /* Implement ‘format-message’ if MESSAGE is true, ‘format’ otherwise. |
| 4163 | If NEW_RESULT, the result is a new string; otherwise, the result | ||
| 4164 | may be one of the arguments. */ | ||
| 4164 | 4165 | ||
| 4165 | static Lisp_Object | 4166 | Lisp_Object |
| 4166 | styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | 4167 | styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message, |
| 4168 | bool new_result) | ||
| 4167 | { | 4169 | { |
| 4168 | ptrdiff_t n; /* The number of the next arg to substitute. */ | 4170 | ptrdiff_t n; /* The number of the next arg to substitute. */ |
| 4169 | char initial_buffer[4000]; | 4171 | char initial_buffer[4000]; |
| @@ -4193,6 +4195,9 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4193 | /* The start and end bytepos in the output string. */ | 4195 | /* The start and end bytepos in the output string. */ |
| 4194 | ptrdiff_t start, end; | 4196 | ptrdiff_t start, end; |
| 4195 | 4197 | ||
| 4198 | /* Whether the argument is a newly created string. */ | ||
| 4199 | bool_bf new_string : 1; | ||
| 4200 | |||
| 4196 | /* Whether the argument is a string with intervals. */ | 4201 | /* Whether the argument is a string with intervals. */ |
| 4197 | bool_bf intervals : 1; | 4202 | bool_bf intervals : 1; |
| 4198 | } *info; | 4203 | } *info; |
| @@ -4342,7 +4347,10 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4342 | memset (&discarded[format0 - format_start], 1, | 4347 | memset (&discarded[format0 - format_start], 1, |
| 4343 | format - format0 - (conversion == '%')); | 4348 | format - format0 - (conversion == '%')); |
| 4344 | if (conversion == '%') | 4349 | if (conversion == '%') |
| 4345 | goto copy_char; | 4350 | { |
| 4351 | new_result = true; | ||
| 4352 | goto copy_char; | ||
| 4353 | } | ||
| 4346 | 4354 | ||
| 4347 | ++n; | 4355 | ++n; |
| 4348 | if (! (n < nargs)) | 4356 | if (! (n < nargs)) |
| @@ -4352,6 +4360,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4352 | if (nspec < ispec) | 4360 | if (nspec < ispec) |
| 4353 | { | 4361 | { |
| 4354 | spec->argument = args[n]; | 4362 | spec->argument = args[n]; |
| 4363 | spec->new_string = false; | ||
| 4355 | spec->intervals = false; | 4364 | spec->intervals = false; |
| 4356 | nspec = ispec; | 4365 | nspec = ispec; |
| 4357 | } | 4366 | } |
| @@ -4369,11 +4378,13 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4369 | { | 4378 | { |
| 4370 | Lisp_Object noescape = conversion == 'S' ? Qnil : Qt; | 4379 | Lisp_Object noescape = conversion == 'S' ? Qnil : Qt; |
| 4371 | spec->argument = arg = Fprin1_to_string (arg, noescape); | 4380 | spec->argument = arg = Fprin1_to_string (arg, noescape); |
| 4381 | spec->new_string = true; | ||
| 4372 | if (STRING_MULTIBYTE (arg) && ! multibyte) | 4382 | if (STRING_MULTIBYTE (arg) && ! multibyte) |
| 4373 | { | 4383 | { |
| 4374 | multibyte = true; | 4384 | multibyte = true; |
| 4375 | goto retry; | 4385 | goto retry; |
| 4376 | } | 4386 | } |
| 4387 | new_result = false; | ||
| 4377 | } | 4388 | } |
| 4378 | conversion = 's'; | 4389 | conversion = 's'; |
| 4379 | } | 4390 | } |
| @@ -4387,6 +4398,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4387 | goto retry; | 4398 | goto retry; |
| 4388 | } | 4399 | } |
| 4389 | spec->argument = arg = Fchar_to_string (arg); | 4400 | spec->argument = arg = Fchar_to_string (arg); |
| 4401 | spec->new_string = true; | ||
| 4390 | } | 4402 | } |
| 4391 | 4403 | ||
| 4392 | if (!EQ (arg, args[n])) | 4404 | if (!EQ (arg, args[n])) |
| @@ -4409,6 +4421,11 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4409 | 4421 | ||
| 4410 | if (conversion == 's') | 4422 | if (conversion == 's') |
| 4411 | { | 4423 | { |
| 4424 | if (format == end && format - format_start == 2 | ||
| 4425 | && (!new_result || spec->new_string) | ||
| 4426 | && ! string_intervals (args[0])) | ||
| 4427 | return arg; | ||
| 4428 | |||
| 4412 | /* handle case (precision[n] >= 0) */ | 4429 | /* handle case (precision[n] >= 0) */ |
| 4413 | 4430 | ||
| 4414 | ptrdiff_t prec = -1; | 4431 | ptrdiff_t prec = -1; |
| @@ -4487,6 +4504,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4487 | if (string_intervals (arg)) | 4504 | if (string_intervals (arg)) |
| 4488 | spec->intervals = arg_intervals = true; | 4505 | spec->intervals = arg_intervals = true; |
| 4489 | 4506 | ||
| 4507 | new_result = true; | ||
| 4490 | continue; | 4508 | continue; |
| 4491 | } | 4509 | } |
| 4492 | } | 4510 | } |
| @@ -4754,6 +4772,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4754 | } | 4772 | } |
| 4755 | spec->end = nchars; | 4773 | spec->end = nchars; |
| 4756 | 4774 | ||
| 4775 | new_result = true; | ||
| 4757 | continue; | 4776 | continue; |
| 4758 | } | 4777 | } |
| 4759 | } | 4778 | } |
| @@ -4772,9 +4791,13 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4772 | } | 4791 | } |
| 4773 | convsrc = format_char == '`' ? uLSQM : uRSQM; | 4792 | convsrc = format_char == '`' ? uLSQM : uRSQM; |
| 4774 | convbytes = 3; | 4793 | convbytes = 3; |
| 4794 | new_result = true; | ||
| 4775 | } | 4795 | } |
| 4776 | else if (format_char == '`' && quoting_style == STRAIGHT_QUOTING_STYLE) | 4796 | else if (format_char == '`' && quoting_style == STRAIGHT_QUOTING_STYLE) |
| 4777 | convsrc = "'"; | 4797 | { |
| 4798 | convsrc = "'"; | ||
| 4799 | new_result = true; | ||
| 4800 | } | ||
| 4778 | else | 4801 | else |
| 4779 | { | 4802 | { |
| 4780 | /* Copy a single character from format to buf. */ | 4803 | /* Copy a single character from format to buf. */ |
| @@ -4798,6 +4821,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4798 | int c = BYTE8_TO_CHAR (format_char); | 4821 | int c = BYTE8_TO_CHAR (format_char); |
| 4799 | convbytes = CHAR_STRING (c, str); | 4822 | convbytes = CHAR_STRING (c, str); |
| 4800 | convsrc = (char *) str; | 4823 | convsrc = (char *) str; |
| 4824 | new_result = true; | ||
| 4801 | } | 4825 | } |
| 4802 | } | 4826 | } |
| 4803 | 4827 | ||
| @@ -4844,6 +4868,9 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4844 | if (bufsize < p - buf) | 4868 | if (bufsize < p - buf) |
| 4845 | emacs_abort (); | 4869 | emacs_abort (); |
| 4846 | 4870 | ||
| 4871 | if (! new_result) | ||
| 4872 | return args[0]; | ||
| 4873 | |||
| 4847 | if (maybe_combine_byte) | 4874 | if (maybe_combine_byte) |
| 4848 | nchars = multibyte_chars_in_text ((unsigned char *) buf, p - buf); | 4875 | nchars = multibyte_chars_in_text ((unsigned char *) buf, p - buf); |
| 4849 | Lisp_Object val = make_specified_string (buf, nchars, p - buf, multibyte); | 4876 | Lisp_Object val = make_specified_string (buf, nchars, p - buf, multibyte); |
diff --git a/src/lisp.h b/src/lisp.h index c5030824427..0c3ca3ae06b 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -3969,6 +3969,7 @@ extern _Noreturn void time_overflow (void); | |||
| 3969 | extern Lisp_Object make_buffer_string (ptrdiff_t, ptrdiff_t, bool); | 3969 | extern Lisp_Object make_buffer_string (ptrdiff_t, ptrdiff_t, bool); |
| 3970 | extern Lisp_Object make_buffer_string_both (ptrdiff_t, ptrdiff_t, ptrdiff_t, | 3970 | extern Lisp_Object make_buffer_string_both (ptrdiff_t, ptrdiff_t, ptrdiff_t, |
| 3971 | ptrdiff_t, bool); | 3971 | ptrdiff_t, bool); |
| 3972 | extern Lisp_Object styled_format (ptrdiff_t, Lisp_Object *, bool, bool); | ||
| 3972 | extern void init_editfns (bool); | 3973 | extern void init_editfns (bool); |
| 3973 | extern void syms_of_editfns (void); | 3974 | extern void syms_of_editfns (void); |
| 3974 | 3975 | ||
diff --git a/src/xdisp.c b/src/xdisp.c index 141275f15a0..86164eb9f6f 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -10194,7 +10194,7 @@ vadd_to_log (char const *format, va_list ap) | |||
| 10194 | for (ptrdiff_t i = 1; i <= nargs; i++) | 10194 | for (ptrdiff_t i = 1; i <= nargs; i++) |
| 10195 | args[i] = va_arg (ap, Lisp_Object); | 10195 | args[i] = va_arg (ap, Lisp_Object); |
| 10196 | Lisp_Object msg = Qnil; | 10196 | Lisp_Object msg = Qnil; |
| 10197 | msg = Fformat_message (nargs, args); | 10197 | msg = styled_format (nargs, args, true, false); |
| 10198 | 10198 | ||
| 10199 | ptrdiff_t len = SBYTES (msg) + 1; | 10199 | ptrdiff_t len = SBYTES (msg) + 1; |
| 10200 | USE_SAFE_ALLOCA; | 10200 | USE_SAFE_ALLOCA; |
| @@ -19525,7 +19525,7 @@ DEFUN ("trace-to-stderr", Ftrace_to_stderr, Strace_to_stderr, 1, MANY, "", | |||
| 19525 | usage: (trace-to-stderr STRING &rest OBJECTS) */) | 19525 | usage: (trace-to-stderr STRING &rest OBJECTS) */) |
| 19526 | (ptrdiff_t nargs, Lisp_Object *args) | 19526 | (ptrdiff_t nargs, Lisp_Object *args) |
| 19527 | { | 19527 | { |
| 19528 | Lisp_Object s = Fformat (nargs, args); | 19528 | Lisp_Object s = styled_format (nargs, args, false, false); |
| 19529 | fwrite (SDATA (s), 1, SBYTES (s), stderr); | 19529 | fwrite (SDATA (s), 1, SBYTES (s), stderr); |
| 19530 | return Qnil; | 19530 | return Qnil; |
| 19531 | } | 19531 | } |