nota leaks fixed

This commit is contained in:
2024-01-31 08:42:15 +00:00
parent 46b86a8e92
commit 262cd50e1a
13 changed files with 217 additions and 162 deletions

View File

@@ -19,7 +19,6 @@ HMM_Vec2 mouse_delta = {0, 0};
struct joystick {
int id;
//GLFWgamepadstate state;
};
static int *downkeys = NULL;

View File

@@ -162,8 +162,8 @@ JSValue js_getpropidx(JSValue v, uint32_t i)
static inline cpBody *js2body(JSValue v) { return js2gameobject(v)->body; }
uint64_t js2uint64(JSValue v) {
uint64_t i;
int64_t js2int64(JSValue v) {
int64_t i;
JS_ToInt64(js, &i, v);
return i;
}
@@ -247,6 +247,8 @@ char *js_nota_decode(JSValue *tmp, char *nota)
case NOTA_TEXT:
nota = nota_read_text(&str, nota);
*tmp = str2js(str);
/* TODO: Avoid malloc and free here */
free(str);
break;
case NOTA_ARR:
nota = nota_read_array(&n, nota);
@@ -258,14 +260,12 @@ char *js_nota_decode(JSValue *tmp, char *nota)
break;
case NOTA_REC:
nota = nota_read_record(&n, nota);
printf("nota object with %d elements\n", n);
*tmp = JS_NewObject(js);
for (int i = 0; i < n; i++) {
nota = nota_read_text(&str, nota);
printf("looking at property %d named %s\n", i, str);
nota = js_nota_decode(&ret2, nota);
JS_SetPropertyStr(js, *tmp, str, ret2);
free(str);
}
break;
case NOTA_INT:
@@ -273,8 +273,10 @@ char *js_nota_decode(JSValue *tmp, char *nota)
*tmp = int2js(n);
break;
case NOTA_SYM:
nota = nota_read_bool(&b, nota);
*tmp = bool2js(b);
nota = nota_read_sym(&b, nota);
if (b == NOTA_NULL) *tmp = JS_UNDEFINED;
else
*tmp = bool2js(b);
break;
default:
case NOTA_FLOAT:
@@ -297,42 +299,44 @@ char *js_nota_encode(JSValue v, char *nota)
switch(tag) {
case JS_TAG_FLOAT64:
// printf("encode float\n");
return nota_write_float(JS_VALUE_GET_FLOAT64(v), nota);
case JS_TAG_INT:
// printf("encode int\n");
return nota_write_int(JS_VALUE_GET_INT(v), nota);
case JS_TAG_STRING:
// printf("encode string\n");
str = js2str(v);
nota = nota_write_text(str, nota);
JS_FreeCString(js, str);
return nota;
case JS_TAG_BOOL:
// printf("encode bool\n");
return nota_write_bool(JS_VALUE_GET_BOOL(v), nota);
return nota_write_sym(JS_VALUE_GET_BOOL(v), nota);
case JS_TAG_UNDEFINED:
return nota_write_sym(NOTA_NULL, nota);
case JS_TAG_NULL:
return nota_write_sym(NOTA_NULL, nota);
case JS_TAG_OBJECT:
if (JS_IsArray(js, v)) {
// printf("encode array\n");
int n = js_arrlen(v);
nota = nota_write_array(n, nota);
for (int i = 0; i < js_arrlen(v); i++)
for (int i = 0; i < n; i++)
nota = js_nota_encode(js_arridx(v, i), nota);
return nota;
}
// printf("encode object\n");
n = JS_GetOwnPropertyNames(js, &ptab, &plen, v, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK);
nota = nota_write_record(plen, nota);
for (int i = 0; i < plen; i++) {
val = JS_GetProperty(js,v,ptab[i].atom);
if (JS_IsUndefined(val) || JS_IsNull(val)) continue;
/* todo: slower than atomtocstring */
str = JS_AtomToCString(js, ptab[i].atom);
// printf("encoding object entry %s\n", str);
JS_FreeAtom(js, ptab[i].atom);
nota = nota_write_text(str, nota);
nota = js_nota_encode(JS_GetProperty(js, v, ptab[i].atom), nota);
JS_FreeCString(js, str);
nota = js_nota_encode(val, nota);
JS_FreeValue(js,val);
}
js_free(js, ptab);
return nota;
}
}
@@ -666,6 +670,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
int *intids = NULL;
gameobject *go = NULL;
JSValue ret = JS_UNDEFINED;
size_t plen = 0;
switch (cmd) {
case 0:
@@ -807,9 +812,9 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break;
case 39:
str = JS_ToCString(js, argv[1]);
str = JS_ToCStringLen(js, &plen, argv[1]);
str2 = JS_ToCString(js, argv[2]);
ret = JS_NewInt64(js, slurp_write(str, str2));
ret = JS_NewInt64(js, slurp_write(str, str2, plen));
break;
case 40:
@@ -883,6 +888,10 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break;
case 60:
str = JS_GetArrayBuffer(js, &plen, argv[1]);
str2 = JS_ToCString(js, argv[2]);
ret = JS_NewInt64(js, slurp_write(str, str2, plen));
str = NULL;
break;
case 61:
@@ -961,6 +970,12 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
arrfree(ids);
break;
case 81:
str = JS_ToCString(js, argv[1]);
d1 = slurp_file(str, &plen);
ret = JS_NewArrayBufferCopy(js, d1, plen);
break;
case 82:
gameobject_draw_debug(js2gameobject(argv[1]));
break;
@@ -1101,15 +1116,15 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break;
case 128:
ret = JS_NewFloat64(js, stm_ns(js2uint64(argv[1])));
ret = JS_NewFloat64(js, stm_ns(js2int64(argv[1])));
break;
case 129:
ret = JS_NewFloat64(js, stm_us(js2uint64(argv[1])));
ret = JS_NewFloat64(js, stm_us(js2int64(argv[1])));
break;
case 130:
ret = JS_NewFloat64(js, stm_ms(js2uint64(argv[1])));
ret = JS_NewFloat64(js, stm_ms(js2int64(argv[1])));
break;
case 131:
@@ -2041,7 +2056,7 @@ JSValue nota_encode(JSContext *js, JSValueConst this, int argc, JSValueConst *ar
if (argc < 1) return JS_UNDEFINED;
JSValue obj = argv[0];
char nota[100000];
char nota[1024*1024]; // 1MB
char *e = js_nota_encode(obj, nota);
return JS_NewArrayBufferCopy(js, nota, e-nota);
@@ -2107,6 +2122,7 @@ void ffi_load() {
sound_proto = JS_NewObject(js);
JS_SetPropertyFunctionList(js, sound_proto, js_sound_funcs, countof(js_sound_funcs));
JS_SetPrototype(js, sound_proto, dsp_node_proto);
JS_FreeValue(js, sound_proto);
QJSCLASSPREP_FUNCS(emitter);
QJSCLASSPREP_FUNCS(warp_gravity);

View File

@@ -1,2 +1,101 @@
#include "kim.h"
#define KIM_CONT 0x80
#define KIM_DATA 0x7f
#define CONTINUE(CHAR) (CHAR>>7)
int utf8_bytes(char *s)
{
int bytes = __builtin_clz(~(*s));
if (!bytes) return 1;
return bytes-24;
}
int utf8_count(char *s)
{
int count = 0;
char *p = s;
while(*s) {
count++;
s += utf8_bytes(s);
}
return count;
}
/* decode and advance s, returning the character cde */
int decode_utf8(char **s) {
int k = **s ? __builtin_clz(~(**s << 24)) : 0; // Count # of leading 1 bits.
int mask = (1 << (8 - k)) - 1; // All 1's with k leading 0's.
int value = **s & mask;
for (++(*s), --k; k > 0 && **s; --k, ++(*s)) { // Note that k = #total bytes, or 0.
value <<= 6;
value += (**s & 0x3F);
}
return value;
}
/* Write and advance s with code in utf-8 */
void encode_utf8(char **s, int code) {
char val[4];
int lead_byte_max = 0x7F;
int val_index = 0;
while (code > lead_byte_max) {
val[val_index++] = (code & 0x3F) | 0x80;
code >>= 6;
lead_byte_max >>= (val_index == 1 ? 2 : 1);
}
val[val_index++] = (code & lead_byte_max) | (~lead_byte_max << 1);
while (val_index--) {
**s = val[val_index];
(*s)++;
}
}
/* write and advance s with code in kim */
void encode_kim(char **s, int code)
{
if (code < KIM_CONT) {
**s = 0 | (KIM_DATA & code);
(*s)++;
return;
}
int bits = ((32 - __builtin_clz(code) + 6) / 7) * 7;
while (bits > 7) {
bits -= 7;
**s = KIM_CONT | KIM_DATA & (code >> bits);
(*s)++;
}
**s = KIM_DATA & code;
(*s)++;
}
/* decode and advance s, returning the character code */
int decode_kim(char **s)
{
int rune = **s & KIM_DATA;
while (CONTINUE(**s)) {
rune <<= 7;
(*s)++;
rune |= **s & KIM_DATA;
}
(*s)++;
return rune;
}
/* write a null-terminated utf8 stream into a kim string */
void utf8_to_kim(char **utf, char **kim)
{
while (**utf)
encode_kim(kim, decode_utf8(utf));
}
/* write number of runes from a kim stream int a utf8 stream */
void kim_to_utf8(char **kim, char **utf, int runes)
{
for (int i = 0; i < runes; i++)
encode_utf8(utf, decode_kim(kim));
}

View File

@@ -1,6 +1,13 @@
#ifndef KIM_H
#define KIM_H
void write_kim_char(char c, char *into);
int utf8_bytes(char *s);
int utf8_count(char *s);
int decode_utf8(char **s);
void encode_utf8(char **s, int code);
void encode_kim(char **s, int code);
int decode_kim(char **s);
void utf8_to_kim(char **utf, char **kim);
void kim_to_utf8(char **kim, char **utf, int runes);
#endif

View File

@@ -4,6 +4,7 @@
#include "string.h"
#include "stdlib.h"
#include "limits.h"
#include "kim.h"
#define NOTA_CONT 0x80
#define NOTA_DATA 0x7f
@@ -15,13 +16,11 @@
#define NOTA_HEAD_DATA 0x0f
#define CONTINUE(CHAR) (CHAR>>7)
#define NOTA_FALSE 0x00
#define NOTA_TRUE 0x01
#define NOTA_PRIVATE 0x08
#define NOTA_SYSTEM 0x09
#define UTF8_DATA 0x3f
/* define this to use native string instead of kim. Bytes are encoded instead of runes */
#define NOTA_UTF8
int nota_type(char *nota) { return *nota & NOTA_TYPE; }
char *nota_skip(char *nota)
@@ -240,136 +239,52 @@ char *nota_write_record(unsigned long long n, char *nota)
return nota_continue_num(n, nota, 4);
}
/* kim is 7, 14, then 21 */
int utf8_bytes(char *s)
char *nota_write_sym(int sym, char *nota)
{
int bytes = __builtin_clz(~(*s));
if (!bytes) return 1;
return bytes-24;
*nota = NOTA_SYM | sym;
return nota+1;
}
int utf8_count(char *s)
char *nota_read_sym(int *sym, char *nota)
{
int count = 0;
char *p = s;
while(*s) {
count++;
s += utf8_bytes(s);
}
return count;
}
int decode_utf8(char **s) {
int k = **s ? __builtin_clz(~(**s << 24)) : 0; // Count # of leading 1 bits.
int mask = (1 << (8 - k)) - 1; // All 1's with k leading 0's.
int value = **s & mask;
for (++(*s), --k; k > 0 && **s; --k, ++(*s)) { // Note that k = #total bytes, or 0.
value <<= 6;
value += (**s & 0x3F);
}
return value;
}
void encode_utf8(char **s, char *end, int code) {
if (code < 255) {
**s = code;
(*s)++;
return;
}
char val[4];
int lead_byte_max = 0x7F;
int val_index = 0;
while (code > lead_byte_max) {
val[val_index++] = (code & 0x3F) | 0x80;
code >>= 6;
lead_byte_max >>= (val_index == 1 ? 2 : 1);
}
val[val_index++] = (code & lead_byte_max) | (~lead_byte_max << 1);
while (val_index-- && *s < end) {
**s = val[val_index];
(*s)++;
}
}
void encode_kim(char **s, char *end, int code)
{
if (code < 255) {
**s = 0 | (NOTA_DATA & code);
(*s)++;
return;
}
int bits = ((32 - __builtin_clz(code) + 6) / 7) * 7;
while (bits > 7) {
bits -= 7;
**s = NOTA_CONT | NOTA_DATA & (code >> bits);
(*s)++;
}
**s = NOTA_DATA & code;
(*s)++;
}
int decode_kim(char **s)
{
int rune = **s & NOTA_DATA;
while (CONTINUE(**s)) {
rune <<= 7;
(*s)++;
rune |= **s & NOTA_DATA;
}
(*s)++;
return rune;
}
char *utf8_to_kim(char *utf, char *kim)
{
while (*utf)
encode_kim(&kim, NULL, decode_utf8(&utf));
return kim;
}
void kim_to_utf8(char *kim, char *utf, int runes)
{
for (int i = 0; i < runes; i++)
encode_utf8(&utf, utf+4, decode_kim(&kim));
*utf = 0;
if (*sym) *sym = (*nota) & 0x0f;
return nota+1;
}
char *nota_read_text(char **text, char *nota)
{
long long chars;
nota = nota_read_num(&chars, nota);
#ifdef NOTA_UTF8
*text = calloc(chars+1,1);
memcpy(*text, nota, chars);
nota += chars;
#else
char utf[chars*4];
kim_to_utf8(nota, utf, chars);
*text = strdup(utf);
char *pp = utf;
kim_to_utf8(&nota, &pp, chars);
*pp = 0;
*text = strdup(utf);
#endif
return nota;
}
char *nota_write_bool(int b, char *nota)
{
*nota = NOTA_SYM | (b ? NOTA_TRUE : NOTA_FALSE);
return nota+1;
}
char *nota_read_bool(int *b, char *nota)
{
if (b) *b = (*nota) & 0x0f;
return nota+1;
}
char *nota_write_text(char *s, char *nota)
{
char *start = nota;
nota[0] = NOTA_TEXT;
long long n = utf8_count(s);
#ifdef NOTA_UTF8
long long n = strlen(s);
nota = nota_continue_num(n,nota,4);
return utf8_to_kim(s, nota);
memcpy(nota, s, n);
return nota+n;
#else
long long n = utf8_count(s);
nota = nota_continue_num(n,nota,4);
utf8_to_kim(&s, &nota);
return nota;
#endif
}

View File

@@ -9,6 +9,12 @@
#define NOTA_INT 0x60
#define NOTA_SYM 0x70
#define NOTA_FALSE 0x00
#define NOTA_TRUE 0x01
#define NOTA_PRIVATE 0x08
#define NOTA_SYSTEM 0x09
#define NOTA_NULL 0x02
typedef struct NOTA {
char *head;
} NOTA;
@@ -21,7 +27,7 @@ char *nota_read_array(long long *len, char *nota);
char *nota_read_record(long long *len, char *nota);
char *nota_read_float(double *d, char *nota);
char *nota_read_int(long long *l, char *nota);
char *nota_read_bool(int *b, char *nota);
char *nota_read_sym(int *sym, char *nota);
void print_nota_hex(char *nota);
@@ -31,6 +37,6 @@ char *nota_write_array(unsigned long long n, char *nota);
char *nota_write_record(unsigned long long n, char *nota);
char *nota_write_float(double n, char *nota);
char *nota_write_int(long long n, char *nota);
char *nota_write_bool(int b, char *nota);
char *nota_write_sym(int sym, char *nota);
#endif

View File

@@ -291,11 +291,12 @@ FILE *fopen_mkdir(const char *path, const char *mode) {
return fopen(path,mode);
}
int slurp_write(const char *txt, const char *filename) {
int slurp_write(const char *txt, const char *filename, size_t len) {
FILE *f = fopen_mkdir(filename, "w");
if (!f) return 1;
fputs(txt, f);
if (len < 0) len = strlen(txt);
fwrite(txt, len, 1, f);
fclose(f);
return 0;
}

View File

@@ -24,7 +24,7 @@ char *dirname(const char *path);
void *slurp_file(const char *filename, size_t *size);
char *slurp_text(const char *filename, size_t *size);
int slurp_write(const char *txt, const char *filename);
int slurp_write(const char *txt, const char *filename, size_t len);
char *seprint(char *fmt, ...);