Skip to content

Commit d40a7f9

Browse files
Improved memory consumption of String.prototype.concat() with numbers.
1 parent 3037c70 commit d40a7f9

File tree

1 file changed

+92
-24
lines changed

1 file changed

+92
-24
lines changed

src/njs_string.c

Lines changed: 92 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -601,56 +601,124 @@ njs_int_t
601601
njs_string_prototype_concat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
602602
njs_index_t unused, njs_value_t *retval)
603603
{
604-
u_char *p, *start;
605-
uint64_t size, length, mask;
604+
605+
#define NUM_TXT_BUF_LEN 512
606+
#define MAX_NUM_TXT_LEN njs_length("-1.7976931348623157e+308")
607+
608+
char *n_p, n_txt[NUM_TXT_BUF_LEN];
609+
double num;
610+
u_char *p;
611+
uint64_t sz, size, length;
606612
njs_int_t ret;
607613
njs_uint_t i;
614+
const char *n_p_max;
608615
njs_string_prop_t string;
609616

617+
618+
n_p_max = n_txt + NUM_TXT_BUF_LEN - 2*(sizeof(uint16_t) + MAX_NUM_TXT_LEN);
619+
n_p = n_txt;
620+
610621
if (njs_is_null_or_undefined(&args[0])) {
611622
njs_type_error(vm, "\"this\" argument is null or undefined");
612623
return NJS_ERROR;
613624
}
614625

615-
for (i = 0; i < nargs; i++) {
616-
if (!njs_is_string(&args[i])) {
617-
ret = njs_value_to_string(vm, &args[i], &args[i]);
618-
if (ret != NJS_OK) {
619-
return ret;
620-
}
621-
}
622-
}
623-
624626
if (nargs == 1) {
625-
njs_string_copy(retval, &args[0]);
627+
njs_value_assign(retval, &args[0]);
626628
return NJS_OK;
627629
}
628630

629631
size = 0;
630632
length = 0;
631-
mask = -1;
632633

633634
for (i = 0; i < nargs; i++) {
634-
(void) njs_string_prop(vm, &string, &args[i]);
635+
if (njs_is_number(&args[i])) {
636+
num = njs_number(&args[i]);
635637

636-
size += string.size;
637-
length += string.length;
638-
}
638+
if (isnan(num)) {
639+
size += njs_length("NaN");
640+
length += njs_length("NaN");
639641

640-
length &= mask;
642+
} else if (isinf(num)) {
643+
if (num < 0) {
644+
size += njs_length("-Infinity");
645+
length += njs_length("-Infinity");
641646

642-
start = njs_string_alloc(vm, retval, size, length);
643-
if (njs_slow_path(start == NULL)) {
647+
} else {
648+
size += njs_length("Infinity");
649+
length += njs_length("Infinity");
650+
}
651+
652+
} else {
653+
sz = njs_dtoa(num, (char *) n_p + sizeof(uint16_t));
654+
655+
if (njs_fast_path(n_p < n_p_max)) {
656+
*((uint16_t *)(n_p)) = sz;
657+
n_p += sizeof(uint16_t) + sz;
658+
}
659+
660+
size += sz;
661+
length += sz;
662+
}
663+
664+
} else {
665+
if (!njs_is_string(&args[i])) {
666+
ret = njs_value_to_string(vm, &args[i], &args[i]);
667+
if (ret != NJS_OK) {
668+
return ret;
669+
}
670+
671+
}
672+
673+
njs_string_prop(vm, &string, &args[i]);
674+
675+
size += string.size;
676+
length += string.length;
677+
}
678+
}
679+
680+
p = njs_string_alloc(vm, retval, size, length);
681+
if (njs_slow_path(p == NULL)) {
644682
return NJS_ERROR;
645683
}
646684

647-
p = start;
685+
n_p = n_txt;
648686

649687
for (i = 0; i < nargs; i++) {
650-
(void) njs_string_prop(vm, &string, &args[i]);
688+
if (njs_is_number(&args[i])) {
689+
num = njs_number(&args[i]);
651690

652-
p = memcpy(p, string.start, string.size);
653-
p += string.size;
691+
if (isnan(num)) {
692+
p = njs_cpymem(p, "NaN", njs_length("NaN"));
693+
694+
} else if (isinf(num)) {
695+
if (num < 0) {
696+
p = njs_cpymem(p, "-Infinity", njs_length("-Infinity"));
697+
698+
} else {
699+
p = njs_cpymem(p, "Infinity", njs_length("Infinity"));
700+
}
701+
702+
} else {
703+
if (njs_fast_path(n_p < n_p_max)) {
704+
length = *((uint16_t *)(n_p));
705+
706+
n_p += sizeof(uint16_t);
707+
p = njs_cpymem(p, n_p, length);
708+
709+
n_p += length;
710+
711+
} else {
712+
sz = njs_dtoa(num, (char *) p);
713+
p += sz;
714+
}
715+
}
716+
717+
} else {
718+
njs_string_prop(vm, &string, &args[i]);
719+
720+
p = njs_cpymem(p, string.start, string.size);
721+
}
654722
}
655723

656724
return NJS_OK;

0 commit comments

Comments
 (0)