on master help sign in
Improve string primitive performance
c0463b7Edwin Brady
rts/idris_gc.c+1−1
@@ -24,7 +24,7 @@ VAL copy(VM* vm, VAL x) {
24 cl = MKFLOATc(vm, x->info.f);
24 cl = MKFLOATc(vm, x->info.f);
25 break;
25 break;
26 case CT_STRING:
26 case CT_STRING:
27− cl = MKSTRc(vm, x->info.str);
27+ cl = MKSTRclen(vm, x->info.str.str, x->info.str.len);
28 break;
28 break;
29 case CT_STROFFSET:
29 case CT_STROFFSET:
30 cl = MKSTROFFc(vm, x->info.str_offset);
30 cl = MKSTROFFc(vm, x->info.str_offset);
rts/idris_rts.c+77−41
@@ -285,19 +285,27 @@ VAL MKSTR(VM* vm, const char* str) {
285 Closure* cl = allocate(sizeof(Closure) + // Type) + sizeof(char*) +
285 Closure* cl = allocate(sizeof(Closure) + // Type) + sizeof(char*) +
286 sizeof(char)*len, 0);
286 sizeof(char)*len, 0);
287 SETTY(cl, CT_STRING);
287 SETTY(cl, CT_STRING);
288− cl -> info.str = (char*)cl + sizeof(Closure);
288+ cl->info.str.str = (char*)cl + sizeof(Closure);
289 if (str == NULL) {
289 if (str == NULL) {
290− cl->info.str = NULL;
290+ cl->info.str.str = NULL;
291 } else {
291 } else {
292− strcpy(cl -> info.str, str);
292+ strcpy(cl->info.str.str, str);
293 }
293 }
294+ cl->info.str.len = len > 0 ? len : 0;
294 return cl;
295 return cl;
295}
296}
296
297
297char* GETSTROFF(VAL stroff) {
298char* GETSTROFF(VAL stroff) {
298 // Assume STROFF
299 // Assume STROFF
299 StrOffset* root = stroff->info.str_offset;
300 StrOffset* root = stroff->info.str_offset;
300− return (root->str->info.str + root->offset);
301+ return (root->str->info.str.str + root->offset);
302+}
303+
304+size_t GETSTROFFLEN(VAL stroff) {
305+ // Assume STROFF
306+ // we're working in char* here so no worries about utf8 char length
307+ StrOffset* root = stroff->info.str_offset;
308+ return (root->str->info.str.len - root->offset);
301}
309}
302
310
303VAL MKCDATA(VM* vm, CHeapItem * item) {
311VAL MKCDATA(VM* vm, CHeapItem * item) {
@@ -342,12 +350,26 @@ VAL MKFLOATc(VM* vm, double val) {
342}
350}
343
351
344VAL MKSTRc(VM* vm, char* str) {
352VAL MKSTRc(VM* vm, char* str) {
353+ int len = strlen(str);
354+
355+ Closure* cl = allocate(sizeof(Closure) + // Type) + sizeof(char*) +
356+ sizeof(char)*len+1, 1);
357+ SETTY(cl, CT_STRING);
358+ cl -> info.str.str = (char*)cl + sizeof(Closure);
359+
360+ strcpy(cl->info.str.str, str);
361+ cl->info.str.len = len;
362+ return cl;
363+}
364+
365+VAL MKSTRclen(VM* vm, char* str, int len) {
345 Closure* cl = allocate(sizeof(Closure) + // Type) + sizeof(char*) +
366 Closure* cl = allocate(sizeof(Closure) + // Type) + sizeof(char*) +
346− sizeof(char)*strlen(str)+1, 1);
367+ sizeof(char)*len+1, 1);
347 SETTY(cl, CT_STRING);
368 SETTY(cl, CT_STRING);
348− cl -> info.str = (char*)cl + sizeof(Closure);
369+ cl -> info.str.str = (char*)cl + sizeof(Closure);
349
370
350− strcpy(cl -> info.str, str);
371+ strcpy(cl->info.str.str, str);
372+ cl->info.str.len = len;
351 return cl;
373 return cl;
352}
374}
353
375
@@ -428,7 +450,7 @@ void dumpVal(VAL v) {
428 printf("] ");
450 printf("] ");
429 break;
451 break;
430 case CT_STRING:
452 case CT_STRING:
431− printf("STR[%s]", v->info.str);
453+ printf("STR[%s]", v->info.str.str);
432 break;
454 break;
433 case CT_FWD:
455 case CT_FWD:
434 printf("CT_FWD ");
456 printf("CT_FWD ");
@@ -490,8 +512,9 @@ VAL idris_castIntStr(VM* vm, VAL i) {
490 int x = (int) GETINT(i);
512 int x = (int) GETINT(i);
491 Closure* cl = allocate(sizeof(Closure) + sizeof(char)*16, 0);
513 Closure* cl = allocate(sizeof(Closure) + sizeof(char)*16, 0);
492 SETTY(cl, CT_STRING);
514 SETTY(cl, CT_STRING);
493− cl -> info.str = (char*)cl + sizeof(Closure);
515+ cl->info.str.str = (char*)cl + sizeof(Closure);
494− sprintf(cl -> info.str, "%d", x);
516+ sprintf(cl->info.str.str, "%d", x);
517+ cl->info.str.len = strlen(cl->info.str.str);
495 return cl;
518 return cl;
496}
519}
497
520
@@ -503,32 +526,33 @@ VAL idris_castBitsStr(VM* vm, VAL i) {
503 case CT_BITS8:
526 case CT_BITS8:
504 // max length 8 bit unsigned int str 3 chars (256)
527 // max length 8 bit unsigned int str 3 chars (256)
505 cl = allocate(sizeof(Closure) + sizeof(char)*4, 0);
528 cl = allocate(sizeof(Closure) + sizeof(char)*4, 0);
506− cl->info.str = (char*)cl + sizeof(Closure);
529+ cl->info.str.str = (char*)cl + sizeof(Closure);
507− sprintf(cl->info.str, "%" PRIu8, (uint8_t)i->info.bits8);
530+ sprintf(cl->info.str.str, "%" PRIu8, (uint8_t)i->info.bits8);
508 break;
531 break;
509 case CT_BITS16:
532 case CT_BITS16:
510 // max length 16 bit unsigned int str 5 chars (65,535)
533 // max length 16 bit unsigned int str 5 chars (65,535)
511 cl = allocate(sizeof(Closure) + sizeof(char)*6, 0);
534 cl = allocate(sizeof(Closure) + sizeof(char)*6, 0);
512− cl->info.str = (char*)cl + sizeof(Closure);
535+ cl->info.str.str = (char*)cl + sizeof(Closure);
513− sprintf(cl->info.str, "%" PRIu16, (uint16_t)i->info.bits16);
536+ sprintf(cl->info.str.str, "%" PRIu16, (uint16_t)i->info.bits16);
514 break;
537 break;
515 case CT_BITS32:
538 case CT_BITS32:
516 // max length 32 bit unsigned int str 10 chars (4,294,967,295)
539 // max length 32 bit unsigned int str 10 chars (4,294,967,295)
517 cl = allocate(sizeof(Closure) + sizeof(char)*11, 0);
540 cl = allocate(sizeof(Closure) + sizeof(char)*11, 0);
518− cl->info.str = (char*)cl + sizeof(Closure);
541+ cl->info.str.str = (char*)cl + sizeof(Closure);
519− sprintf(cl->info.str, "%" PRIu32, (uint32_t)i->info.bits32);
542+ sprintf(cl->info.str.str, "%" PRIu32, (uint32_t)i->info.bits32);
520 break;
543 break;
521 case CT_BITS64:
544 case CT_BITS64:
522 // max length 64 bit unsigned int str 20 chars (18,446,744,073,709,551,615)
545 // max length 64 bit unsigned int str 20 chars (18,446,744,073,709,551,615)
523 cl = allocate(sizeof(Closure) + sizeof(char)*21, 0);
546 cl = allocate(sizeof(Closure) + sizeof(char)*21, 0);
524− cl->info.str = (char*)cl + sizeof(Closure);
547+ cl->info.str.str = (char*)cl + sizeof(Closure);
525− sprintf(cl->info.str, "%" PRIu64, (uint64_t)i->info.bits64);
548+ sprintf(cl->info.str.str, "%" PRIu64, (uint64_t)i->info.bits64);
526 break;
549 break;
527 default:
550 default:
528 fprintf(stderr, "Fatal Error: ClosureType %d, not an integer type", ty);
551 fprintf(stderr, "Fatal Error: ClosureType %d, not an integer type", ty);
529 exit(EXIT_FAILURE);
552 exit(EXIT_FAILURE);
530 }
553 }
531
554
555+ cl->info.str.len = strlen(cl->info.str.str);
532 SETTY(cl, CT_STRING);
556 SETTY(cl, CT_STRING);
533 return cl;
557 return cl;
534}
558}
@@ -545,8 +569,10 @@ VAL idris_castStrInt(VM* vm, VAL i) {
545VAL idris_castFloatStr(VM* vm, VAL i) {
569VAL idris_castFloatStr(VM* vm, VAL i) {
546 Closure* cl = allocate(sizeof(Closure) + sizeof(char)*32, 0);
570 Closure* cl = allocate(sizeof(Closure) + sizeof(char)*32, 0);
547 SETTY(cl, CT_STRING);
571 SETTY(cl, CT_STRING);
548− cl -> info.str = (char*)cl + sizeof(Closure);
572+ cl->info.str.str = (char*)cl + sizeof(Closure);
549− snprintf(cl -> info.str, 32, "%.16g", GETFLOAT(i));
573+ snprintf(cl->info.str.str, 32, "%.16g", GETFLOAT(i));
574+
575+ cl->info.str.len = strlen(cl->info.str.str);
550 return cl;
576 return cl;
551}
577}
552
578
@@ -559,11 +585,13 @@ VAL idris_concat(VM* vm, VAL l, VAL r) {
559 char *ls = GETSTR(l);
585 char *ls = GETSTR(l);
560 // dumpVal(l);
586 // dumpVal(l);
561 // printf("\n");
587 // printf("\n");
562− Closure* cl = allocate(sizeof(Closure) + strlen(ls) + strlen(rs) + 1, 0);
588+ Closure* cl = allocate(sizeof(Closure) + GETSTRLEN(l) + GETSTRLEN(r) + 1, 0);
563 SETTY(cl, CT_STRING);
589 SETTY(cl, CT_STRING);
564− cl -> info.str = (char*)cl + sizeof(Closure);
590+ cl->info.str.str = (char*)cl + sizeof(Closure);
565− strcpy(cl -> info.str, ls);
591+ strcpy(cl->info.str.str, ls);
566− strcat(cl -> info.str, rs);
592+ strcat(cl->info.str.str, rs);
593+
594+ cl->info.str.len = GETSTRLEN(l) + GETSTRLEN(r);
567 return cl;
595 return cl;
568}
596}
569
597
@@ -670,21 +698,26 @@ VAL idris_strTail(VM* vm, VAL str) {
670VAL idris_strCons(VM* vm, VAL x, VAL xs) {
698VAL idris_strCons(VM* vm, VAL x, VAL xs) {
671 char *xstr = GETSTR(xs);
699 char *xstr = GETSTR(xs);
672 int xval = GETINT(x);
700 int xval = GETINT(x);
701+ int xlen = GETSTRLEN(xs);
702+
673 if ((xval & 0x80) == 0) { // ASCII char
703 if ((xval & 0x80) == 0) { // ASCII char
674 Closure* cl = allocate(sizeof(Closure) +
704 Closure* cl = allocate(sizeof(Closure) +
675− strlen(xstr) + 2, 0);
705+ xlen + 2, 0);
676 SETTY(cl, CT_STRING);
706 SETTY(cl, CT_STRING);
677− cl -> info.str = (char*)cl + sizeof(Closure);
707+ cl->info.str.str = (char*)cl + sizeof(Closure);
678− cl -> info.str[0] = (char)(GETINT(x));
708+ cl->info.str.str[0] = (char)(GETINT(x));
679− strcpy(cl -> info.str+1, xstr);
709+ strcpy(cl->info.str.str+1, xstr);
710+ cl->info.str.len = xlen + 1;
680 return cl;
711 return cl;
681 } else {
712 } else {
682 char *init = idris_utf8_fromChar(xval);
713 char *init = idris_utf8_fromChar(xval);
714+ int newlen = strlen(init) + xlen;
683− Closure* cl = allocate(sizeof(Closure) + strlen(init) + strlen(xstr) + 1, 0);
715+ Closure* cl = allocate(sizeof(Closure) + newlen + 1, 0);
684 SETTY(cl, CT_STRING);
716 SETTY(cl, CT_STRING);
685− cl -> info.str = (char*)cl + sizeof(Closure);
717+ cl->info.str.str = (char*)cl + sizeof(Closure);
686− strcpy(cl -> info.str, init);
718+ strcpy(cl->info.str.str, init);
687− strcat(cl -> info.str, xstr);
719+ strcat(cl->info.str.str, xstr);
720+ cl->info.str.len = newlen;
688 free(init);
721 free(init);
689 return cl;
722 return cl;
690 }
723 }
@@ -701,7 +734,7 @@ VAL idris_substr(VM* vm, VAL offset, VAL length, VAL str) {
701 char* str_val = GETSTR(str);
734 char* str_val = GETSTR(str);
702
735
703 // If the substring is a suffix, use idris_strShift to avoid reallocating
736 // If the substring is a suffix, use idris_strShift to avoid reallocating
704− if (offset_val + length_val >= strlen(str_val)) {
737+ if (offset_val + length_val >= GETSTRLEN(str)) {
705 return idris_strShift(vm, str, offset_val);
738 return idris_strShift(vm, str, offset_val);
706 }
739 }
707 else {
740 else {
@@ -709,20 +742,23 @@ VAL idris_substr(VM* vm, VAL offset, VAL length, VAL str) {
709 char *end = idris_utf8_advance(start, length_val);
742 char *end = idris_utf8_advance(start, length_val);
710 Closure* newstr = allocate(sizeof(Closure) + (end - start) +1, 0);
743 Closure* newstr = allocate(sizeof(Closure) + (end - start) +1, 0);
711 SETTY(newstr, CT_STRING);
744 SETTY(newstr, CT_STRING);
712− newstr -> info.str = (char*)newstr + sizeof(Closure);
745+ newstr->info.str.str = (char*)newstr + sizeof(Closure);
713− memcpy(newstr -> info.str, start, end - start);
746+ memcpy(newstr->info.str.str, start, end - start);
714− *(newstr -> info.str + (end - start) + 1) = '\0';
747+ *(newstr->info.str.str + (end - start) + 1) = '\0';
748+ newstr->info.str.len = strlen(newstr->info.str.str);
715 return newstr;
749 return newstr;
716 }
750 }
717}
751}
718
752
719VAL idris_strRev(VM* vm, VAL str) {
753VAL idris_strRev(VM* vm, VAL str) {
720 char *xstr = GETSTR(str);
754 char *xstr = GETSTR(str);
755+ int xlen = GETSTRLEN(str);
756+
721− Closure* cl = allocate(sizeof(Closure) +
757+ Closure* cl = allocate(sizeof(Closure) + xlen + 1, 0);
722− strlen(xstr) + 1, 0);
723 SETTY(cl, CT_STRING);
758 SETTY(cl, CT_STRING);
724− cl->info.str = (char*)cl + sizeof(Closure);
759+ cl->info.str.str = (char*)cl + sizeof(Closure);
760+ cl->info.str.len = xlen;
725− idris_utf8_rev(xstr, cl->info.str);
761+ idris_utf8_rev(xstr, cl->info.str.str);
726 return cl;
762 return cl;
727}
763}
728
764
@@ -832,7 +868,7 @@ VAL doCopyTo(VM* vm, VAL x) {
832 cl = MKFLOATc(vm, x->info.f);
868 cl = MKFLOATc(vm, x->info.f);
833 break;
869 break;
834 case CT_STRING:
870 case CT_STRING:
835− cl = MKSTRc(vm, x->info.str);
871+ cl = MKSTRc(vm, x->info.str.str);
836 break;
872 break;
837 case CT_BIGINT:
873 case CT_BIGINT:
838 cl = MKBIGMc(vm, x->info.ptr);
874 cl = MKBIGMc(vm, x->info.ptr);
rts/idris_rts.h+10−2
@@ -42,6 +42,11 @@ typedef struct {
42 size_t offset;
42 size_t offset;
43} StrOffset;
43} StrOffset;
44
44
45+typedef struct {
46+ char* str;
47+ size_t len; // Cached strlen (we do 'strlen' a lot)
48+} String;
49+
45// A foreign pointer, managed by the idris GC
50// A foreign pointer, managed by the idris GC
46typedef struct {
51typedef struct {
47 size_t size;
52 size_t size;
@@ -59,7 +64,7 @@ typedef struct Closure {
59 con c;
64 con c;
60 int i;
65 int i;
61 double f;
66 double f;
62− char* str;
67+ String str;
63 StrOffset* str_offset;
68 StrOffset* str_offset;
64 void* ptr;
69 void* ptr;
65 uint8_t bits8;
70 uint8_t bits8;
@@ -182,7 +187,8 @@ typedef void(*func)(VM*, VAL*);
182#define ALIGN(__p, __alignment) ((__p + __alignment - 1) & ~(__alignment - 1))
187#define ALIGN(__p, __alignment) ((__p + __alignment - 1) & ~(__alignment - 1))
183
188
184// Retrieving values
189// Retrieving values
185−#define GETSTR(x) (ISSTR(x) ? (((VAL)(x))->info.str) : GETSTROFF(x))
190+#define GETSTR(x) (ISSTR(x) ? (((VAL)(x))->info.str.str) : GETSTROFF(x))
191+#define GETSTRLEN(x) (ISSTR(x) ? (((VAL)(x))->info.str.len) : GETSTROFFLEN(x))
186#define GETPTR(x) (((VAL)(x))->info.ptr)
192#define GETPTR(x) (((VAL)(x))->info.ptr)
187#define GETMPTR(x) (((VAL)(x))->info.mptr->data)
193#define GETMPTR(x) (((VAL)(x))->info.mptr->data)
188#define GETFLOAT(x) (((VAL)(x))->info.f)
194#define GETFLOAT(x) (((VAL)(x))->info.f)
@@ -255,11 +261,13 @@ VAL MKCDATA(VM* vm, CHeapItem * item);
255VAL MKFLOATc(VM* vm, double val);
261VAL MKFLOATc(VM* vm, double val);
256VAL MKSTROFFc(VM* vm, StrOffset* off);
262VAL MKSTROFFc(VM* vm, StrOffset* off);
257VAL MKSTRc(VM* vm, char* str);
263VAL MKSTRc(VM* vm, char* str);
264+VAL MKSTRclen(VM* vm, char* str, int len);
258VAL MKPTRc(VM* vm, void* ptr);
265VAL MKPTRc(VM* vm, void* ptr);
259VAL MKMPTRc(VM* vm, void* ptr, size_t size);
266VAL MKMPTRc(VM* vm, void* ptr, size_t size);
260VAL MKCDATAc(VM* vm, CHeapItem * item);
267VAL MKCDATAc(VM* vm, CHeapItem * item);
261
268
262char* GETSTROFF(VAL stroff);
269char* GETSTROFF(VAL stroff);
270+size_t GETSTROFFLEN(VAL stroff);
263
271
264// #define SETTAG(x, a) (x)->info.c.tag = (a)
272// #define SETTAG(x, a) (x)->info.c.tag = (a)
265#define SETARG(x, i, a) ((x)->info.c.args)[i] = ((VAL)(a))
273#define SETARG(x, i, a) ((x)->info.c.args)[i] = ((VAL)(a))