zero copy blob

This commit is contained in:
2026-02-20 14:06:42 -06:00
parent c5ad4f0a99
commit ebfc89e072
11 changed files with 160 additions and 153 deletions

View File

@@ -102,18 +102,15 @@ JSC_CCALL(fd_read,
if (argc > 1)
size = js2number(js, argv[1]);
void *buf = malloc(size);
if (!buf)
return JS_RaiseDisrupt(js, "malloc failed");
ssize_t bytes_read = read(fd, buf, size);
if (bytes_read < 0) {
free(buf);
void *out;
ret = js_new_blob_alloc(js, size, &out);
if (JS_IsException(ret)) return ret;
ssize_t bytes_read = read(fd, out, size);
if (bytes_read < 0)
return JS_RaiseDisrupt(js, "read failed: %s", strerror(errno));
}
ret = js_new_blob_stoned_copy(js, buf, bytes_read);
free(buf);
js_blob_stone(ret, bytes_read);
return ret;
)
@@ -128,39 +125,48 @@ JSC_SCALL(fd_slurp,
size_t size = st.st_size;
if (size == 0)
return js_new_blob_stoned_copy(js, NULL, 0);
#ifndef _WIN32
int fd = open(str, O_RDONLY);
if (fd < 0)
return JS_RaiseDisrupt(js, "open failed: %s", strerror(errno));
void *data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
if (data == MAP_FAILED) {
close(fd);
return JS_RaiseDisrupt(js, "mmap failed: %s", strerror(errno));
void *out;
ret = js_new_blob_alloc(js, size, &out);
if (JS_IsException(ret)) { close(fd); return ret; }
size_t total = 0;
while (total < size) {
ssize_t n = read(fd, (uint8_t *)out + total, size - total);
if (n < 0) {
if (errno == EINTR) continue;
close(fd);
return JS_RaiseDisrupt(js, "read failed: %s", strerror(errno));
}
if (n == 0) break;
total += n;
}
ret = js_new_blob_stoned_copy(js, data, size);
munmap(data, size);
close(fd);
js_blob_stone(ret, total);
#else
// Windows: use memory mapping for optimal performance
HANDLE hFile = CreateFileA(str, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return JS_RaiseDisrupt(js, "CreateFile failed: %lu", GetLastError());
HANDLE hMapping = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (hMapping == NULL) {
CloseHandle(hFile);
return JS_RaiseDisrupt(js, "CreateFileMapping failed: %lu", GetLastError());
}
void *data = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
if (data == NULL) {
CloseHandle(hMapping);
CloseHandle(hFile);
return JS_RaiseDisrupt(js, "MapViewOfFile failed: %lu", GetLastError());
}
ret = js_new_blob_stoned_copy(js, data, size);
UnmapViewOfFile(data);
CloseHandle(hMapping);

View File

@@ -8,26 +8,25 @@
JSC_CCALL(kim_encode,
const char *utf8_str = JS_ToCString(js, argv[0]);
if (!utf8_str) return JS_EXCEPTION;
// Count runes to estimate kim buffer size
int rune_count = utf8_count(utf8_str);
// Allocate kim buffer (worst case: 5 bytes per rune)
// Allocate blob (worst case: 5 bytes per rune)
size_t kim_size = rune_count * 5;
char *kim_buffer = malloc(kim_size);
char *kim_ptr = kim_buffer;
// Encode utf8 to kim
void *out;
ret = js_new_blob_alloc(js, kim_size, &out);
if (JS_IsException(ret)) { JS_FreeCString(js, utf8_str); return ret; }
// Encode utf8 to kim directly into blob
char *kim_ptr = (char *)out;
long long runes_encoded;
utf8_to_kim(&utf8_str, &kim_ptr, &runes_encoded);
// Calculate actual size used
size_t actual_size = kim_ptr - kim_buffer;
// Create blob with the encoded data
ret = js_new_blob_stoned_copy(js, kim_buffer, actual_size);
free(kim_buffer);
// Stone with actual size used
size_t actual_size = kim_ptr - (char *)out;
js_blob_stone(ret, actual_size);
JS_FreeCString(js, utf8_str);
)