@@ -475,6 +475,354 @@ VAL idris_strRev(VM* vm, VAL str) {
475 return cl;
475 return cl;
478+VAL MKBUFFERc(VM* vm, Buffer* buf) {
479+ Closure* cl = allocate(vm, sizeof(Closure) + sizeof *buf + buf->cap, 1);
481+ cl->info.buf = (Buffer*)((void*)cl + sizeof(Closure));
482+ memmove(cl->info.buf, buf, sizeof *buf + buf->fill);
486+static VAL make_buf_offset(VM* vm, BufOffset* off, int outerlock) {
487+ Closure* cl = allocate(vm, sizeof(Closure) + sizeof *off, outerlock);
488+ SETTY(cl, BUFOFFSET);
489+ cl->info.buf_offset = (BufOffset*)((void*)cl + sizeof(Closure));
490+ memmove(cl->info.buf_offset, off, sizeof *off);
494+static VAL MKBUFOFFSET(VM* vm, BufOffset* off) {
495+ return make_buf_offset(vm, off, 0);
498+VAL MKBUFOFFSETc(VM* vm, BufOffset* off) {
499+ return make_buf_offset(vm, off, 1);
502+static VAL internal_allocate(VM *vm, size_t hint) {
503+ size_t size = hint + sizeof(Closure) + sizeof(Buffer);
505+ // Round up to a power of 2
508+ for (i = 0; i <= sizeof size; ++i)
509+ size |= size >> (1 << i);
512+ Closure* cl = allocate(vm, size, 0);
514+ cl->info.buf = (Buffer*)((void*)cl + sizeof(Closure));
515+ cl->info.buf->cap = size - (sizeof(Closure) + sizeof(Buffer));
519+// Following functions cast uint64_t to size_t, which may narrow!
520+VAL idris_allocate(VM* vm, VAL hint) {
521+ Closure* cl = internal_allocate(vm, hint->info.bits64);
522+ cl->info.buf->fill = 0;
526+VAL idris_copy(VM* vm, VAL len, VAL src) {
527+ size_t length = len->info.bits64;
528+ Closure* cl = internal_allocate(vm, length);
529+ memmove(cl->info.buf->store, (GETTY(src) == BUFOFFSET ?
530+ src->info.buf_offset->buf->info.buf->store + src->info.buf_offset->offset :
531+ src->info.buf->store
533+ cl->info.buf->fill = length;
537+static void internal_memset(void *dest, const void *src, size_t size, size_t num) {
539+ memmove(dest, src, size);
544+static void internal_prepare_append(VM* vm, VAL buf, size_t bufLen, size_t appLen, void** storePtr, Closure** valPtr) {
545+ size_t totalLen = bufLen + appLen;
546+ // Might be able to get rid of some duplication here...
547+ if (GETTY(buf) == BUFOFFSET) {
548+ if (buf->info.buf_offset->offset + bufLen !=
549+ buf->info.buf_offset->buf->info.buf->fill ||
550+ buf->info.buf_offset->offset + totalLen >
551+ buf->info.buf_offset->buf->info.buf->cap) {
552+ // We're not at the fill or are over cap, so need a new buffer
553+ *valPtr = internal_allocate(vm, totalLen);
554+ memmove((*valPtr)->info.buf->store,
555+ buf->info.buf_offset->buf->info.buf->store + buf->info.buf_offset->offset,
557+ (*valPtr)->info.buf->fill = totalLen;
558+ *storePtr = (*valPtr)->info.buf->store + bufLen;
560+ // Hooray, can just bump the fill
561+ *valPtr = MKBUFOFFSET(vm, buf->info.buf_offset);
562+ buf->info.buf_offset->buf->info.buf->fill += appLen;
563+ *storePtr = buf->info.buf_offset->buf->info.buf->store + buf->info.buf_offset->offset + bufLen;
567+ if (bufLen != buf->info.buf->fill ||
568+ totalLen > buf->info.buf->cap) {
569+ // We're not at the fill or are over cap, so need a new buffer
570+ *valPtr = internal_allocate(vm, totalLen);
571+ newBuf = (*valPtr)->info.buf;
572+ memmove(newBuf->store,
573+ buf->info.buf->store,
575+ newBuf->fill = totalLen;
577+ // Hooray, can just bump the fill
578+ BufOffset off = { buf, 0 };
579+ *valPtr = MKBUFOFFSET(vm, &off);
580+ newBuf = buf->info.buf;
581+ newBuf->fill += appLen;
583+ *storePtr = newBuf->store + bufLen;
587+VAL idris_appendBuffer(VM* vm, VAL fst, VAL fstLen, VAL cnt, VAL sndLen, VAL snd) {
588+ size_t firstLength = fstLen->info.bits64;
589+ size_t secondLength = sndLen->info.bits64;
590+ size_t count = cnt->info.bits64;
593+ internal_prepare_append(vm, fst, firstLength, count * secondLength, &store, &cl);
594+ internal_memset(store, GETTY(snd) == BUFOFFSET ?
595+ snd->info.buf_offset->buf->info.buf->store + snd->info.buf_offset->offset :
596+ snd->info.buf->store
597+ , secondLength, count);
601+VAL idris_peekBuffer(VM* vm, VAL src, VAL off) {
602+ size_t offset = off->info.bits64;
604+ if (GETTY(src) == BUFOFFSET) {
605+ b.buf = src->info.buf_offset->buf;
606+ b.offset = src->info.buf_offset->offset + offset;
611+ return MKBUFOFFSET(vm, &b);
614+// Special cased because we can use memset
615+VAL idris_appendB8Native(VM* vm, VAL buf, VAL len, VAL cnt, VAL val) {
616+ size_t bufLen = len->info.bits64;
617+ size_t count = cnt->info.bits64;
620+ internal_prepare_append(vm, buf, bufLen, count, &store, &cl);
621+ memset(store, val->info.bits8, count);
625+VAL idris_appendB8LE(VM* vm, VAL buf, VAL len, VAL cnt, VAL val) {
626+ return idris_appendB8Native(vm, buf, len, cnt, val);
629+VAL idris_appendB8BE(VM* vm, VAL buf, VAL len, VAL cnt, VAL val) {
630+ return idris_appendB8Native(vm, buf, len, cnt, val);
633+static VAL internal_append_bits(VM* vm, VAL buf, VAL bufLen, VAL cnt, const void* val, size_t val_len) {
634+ size_t len = bufLen->info.bits64;
635+ size_t count = cnt->info.bits64;
638+ internal_prepare_append(vm, buf, len, count * val_len, &store, &cl);
639+ internal_memset(store, val, val_len, count);
643+VAL idris_appendB16Native(VM* vm, VAL buf, VAL len, VAL cnt, VAL val) {
644+ return internal_append_bits(vm, buf, len, cnt, &val->info.bits16, sizeof val->info.bits16);
647+VAL idris_appendB16LE(VM* vm, VAL buf, VAL len, VAL cnt, VAL val) {
648+ // On gcc 4.8 -O3 compiling for x86_64, using leVal like this is
649+ // optimized away. Presumably the same holds for other sizes and
650+ // conversly on BE systems
651+ unsigned char leVal[sizeof val] = { val->info.bits16
652+ , (val->info.bits16 >> 8)
654+ return internal_append_bits(vm, buf, len, cnt, leVal, sizeof leVal);
657+VAL idris_appendB16BE(VM* vm, VAL buf, VAL len, VAL cnt, VAL val) {
658+ unsigned char beVal[sizeof val] = { (val->info.bits16 >> 8)
661+ return internal_append_bits(vm, buf, len, cnt, beVal, sizeof beVal);
664+VAL idris_appendB32Native(VM* vm, VAL buf, VAL len, VAL cnt, VAL val) {
665+ return internal_append_bits(vm, buf, len, cnt, &val->info.bits32, sizeof val->info.bits32);
668+VAL idris_appendB32LE(VM* vm, VAL buf, VAL len, VAL cnt, VAL val) {
669+ unsigned char leVal[sizeof val] = { val->info.bits32
670+ , (val->info.bits32 >> 8)
671+ , (val->info.bits32 >> 16)
672+ , (val->info.bits32 >> 24)
674+ return internal_append_bits(vm, buf, len, cnt, leVal, sizeof leVal);
677+VAL idris_appendB32BE(VM* vm, VAL buf, VAL len, VAL cnt, VAL val) {
678+ unsigned char beVal[sizeof val] = { (val->info.bits32 >> 24)
679+ , (val->info.bits32 >> 16)
680+ , (val->info.bits32 >> 8)
683+ return internal_append_bits(vm, buf, len, cnt, beVal, sizeof beVal);
686+VAL idris_appendB64Native(VM* vm, VAL buf, VAL len, VAL cnt, VAL val) {
687+ return internal_append_bits(vm, buf, len, cnt, &val->info.bits64, sizeof val->info.bits64);
690+VAL idris_appendB64LE(VM* vm, VAL buf, VAL len, VAL cnt, VAL val) {
691+ unsigned char leVal[sizeof val] = { val->info.bits64
692+ , (val->info.bits64 >> 8)
693+ , (val->info.bits64 >> 16)
694+ , (val->info.bits64 >> 24)
695+ , (val->info.bits64 >> 32)
696+ , (val->info.bits64 >> 40)
697+ , (val->info.bits64 >> 48)
698+ , (val->info.bits64 >> 56)
700+ return internal_append_bits(vm, buf, len, cnt, leVal, sizeof leVal);
703+VAL idris_appendB64BE(VM* vm, VAL buf, VAL len, VAL cnt, VAL val) {
704+ unsigned char beVal[sizeof val] = { (val->info.bits64 >> 56)
705+ , (val->info.bits64 >> 48)
706+ , (val->info.bits64 >> 40)
707+ , (val->info.bits64 >> 32)
708+ , (val->info.bits64 >> 24)
709+ , (val->info.bits64 >> 16)
710+ , (val->info.bits64 >> 8)
713+ return internal_append_bits(vm, buf, len, cnt, beVal, sizeof beVal);
716+VAL idris_peekB8Native(VM* vm, VAL buf, VAL off) {
717+ size_t offset = off->info.bits64;
718+ uint8_t* val = GETTY(buf) == BUFOFFSET ?
719+ buf->info.buf_offset->buf->info.buf->store + buf->info.buf_offset->offset + offset :
720+ buf->info.buf->store + offset;
721+ return MKB8(vm, *val);
724+VAL idris_peekB8LE(VM* vm, VAL buf, VAL off) {
725+ return idris_peekB8Native(vm, buf, off);
728+VAL idris_peekB8BE(VM* vm, VAL buf, VAL off) {
729+ return idris_peekB8Native(vm, buf, off);
732+VAL idris_peekB16Native(VM* vm, VAL buf, VAL off) {
733+ size_t offset = off->info.bits64;
734+ uint16_t* val = (uint16_t *) ((GETTY(buf) == BUFOFFSET) ?
735+ buf->info.buf_offset->buf->info.buf->store + buf->info.buf_offset->offset + offset :
736+ buf->info.buf->store + offset);
737+ return MKB16(vm, *val);
740+VAL idris_peekB16LE(VM* vm, VAL buf, VAL off) {
741+ size_t offset = off->info.bits64;
742+ unsigned char* val = (GETTY(buf) == BUFOFFSET) ?
743+ buf->info.buf_offset->buf->info.buf->store + buf->info.buf_offset->offset + offset :
744+ buf->info.buf->store + offset;
745+ return MKB16(vm, ((uint16_t) val[0]) +
746+ (((uint16_t) val[1]) << 8));
749+VAL idris_peekB16BE(VM* vm, VAL buf, VAL off) {
750+ size_t offset = off->info.bits64;
751+ unsigned char* val = (GETTY(buf) == BUFOFFSET) ?
752+ buf->info.buf_offset->buf->info.buf->store + buf->info.buf_offset->offset + offset :
753+ buf->info.buf->store + offset;
754+ return MKB16(vm, ((uint16_t) val[1]) +
755+ (((uint16_t) val[0]) << 8));
758+VAL idris_peekB32Native(VM* vm, VAL buf, VAL off) {
759+ size_t offset = off->info.bits64;
760+ uint32_t* val = (uint32_t *) ((GETTY(buf) == BUFOFFSET) ?
761+ buf->info.buf_offset->buf->info.buf->store + buf->info.buf_offset->offset + offset :
762+ buf->info.buf->store + offset);
763+ return MKB32(vm, *val);
766+VAL idris_peekB32LE(VM* vm, VAL buf, VAL off) {
767+ size_t offset = off->info.bits64;
768+ unsigned char* val = (GETTY(buf) == BUFOFFSET) ?
769+ buf->info.buf_offset->buf->info.buf->store + buf->info.buf_offset->offset + offset :
770+ buf->info.buf->store + offset;
771+ return MKB32(vm, ((uint32_t) val[0]) +
772+ (((uint32_t) val[1]) << 8) +
773+ (((uint32_t) val[2]) << 16) +
774+ (((uint32_t) val[3]) << 24));
777+VAL idris_peekB32BE(VM* vm, VAL buf, VAL off) {
778+ size_t offset = off->info.bits64;
779+ unsigned char* val = (GETTY(buf) == BUFOFFSET) ?
780+ buf->info.buf_offset->buf->info.buf->store + buf->info.buf_offset->offset + offset :
781+ buf->info.buf->store + offset;
782+ return MKB32(vm, ((uint32_t) val[3]) +
783+ (((uint32_t) val[2]) << 8) +
784+ (((uint32_t) val[1]) << 16) +
785+ (((uint32_t) val[0]) << 24));
788+VAL idris_peekB64Native(VM* vm, VAL buf, VAL off) {
789+ size_t offset = off->info.bits64;
790+ uint64_t* val = (uint64_t *) ((GETTY(buf) == BUFOFFSET) ?
791+ buf->info.buf_offset->buf->info.buf->store + buf->info.buf_offset->offset + offset :
792+ buf->info.buf->store + offset);
793+ return MKB64(vm, *val);
796+VAL idris_peekB64LE(VM* vm, VAL buf, VAL off) {
797+ size_t offset = off->info.bits64;
798+ unsigned char* val = (GETTY(buf) == BUFOFFSET) ?
799+ buf->info.buf_offset->buf->info.buf->store + buf->info.buf_offset->offset + offset :
800+ buf->info.buf->store + offset;
801+ return MKB64(vm, ((uint64_t) val[0]) +
802+ (((uint64_t) val[1]) << 8) +
803+ (((uint64_t) val[2]) << 16) +
804+ (((uint64_t) val[3]) << 24) +
805+ (((uint64_t) val[4]) << 32) +
806+ (((uint64_t) val[5]) << 40) +
807+ (((uint64_t) val[6]) << 48) +
808+ (((uint64_t) val[7]) << 56));
811+VAL idris_peekB64BE(VM* vm, VAL buf, VAL off) {
812+ size_t offset = off->info.bits64;
813+ unsigned char* val = (GETTY(buf) == BUFOFFSET) ?
814+ buf->info.buf_offset->buf->info.buf->store + buf->info.buf_offset->offset + offset :
815+ buf->info.buf->store + offset;
816+ return MKB64(vm, ((uint64_t) val[7]) +
817+ (((uint64_t) val[6]) << 8) +
818+ (((uint64_t) val[5]) << 16) +
819+ (((uint64_t) val[4]) << 24) +
820+ (((uint64_t) val[3]) << 32) +
821+ (((uint64_t) val[2]) << 40) +
822+ (((uint64_t) val[1]) << 48) +
823+ (((uint64_t) val[0]) << 56));
478typedef struct {
826typedef struct {
479 VM* vm; // thread's VM
827 VM* vm; // thread's VM
480 VM* callvm; // calling thread's VM
828 VM* callvm; // calling thread's VM
@@ -552,6 +900,21 @@ VAL copyTo(VM* vm, VAL x) {
552 case STRING:
900 case STRING:
553 cl = MKSTRc(vm, x->info.str);
901 cl = MKSTRc(vm, x->info.str);
904+ cl = MKBUFFERc(vm, x->info.buf);
907+ // The underlying Buffer might already exist in the new heap
908+ // but we can't do anything reasonable about it
909+ if (x->info.buf_offset->offset == 0)
910+ cl = MKBUFFERc(vm, x->info.buf_offset->buf->info.buf);
912+ // Could theoretically make this a bit more efficient
913+ // by allocating the BufOffset and Buffer together
914+ cl = MKBUFOFFSETc(vm, x->info.buf_offset);
915+ cl->info.buf_offset->buf = MKBUFFERc(vm, x->info.buf_offset->buf->info.buf);
555 case BIGINT:
918 case BIGINT:
556 cl = MKBIGMc(vm, x->info.ptr);
919 cl = MKBIGMc(vm, x->info.ptr);