mirror of
https://github.com/janet-lang/janet
synced 2026-10-09 01:01:41 +00:00
Allow loading bytecode lazily on first use.
Ugly code, but avoids copying the bytecode until needed. Relatively small but measurable reduction in memory usage for "hello world" style programs.
This commit is contained in:
@@ -408,6 +408,9 @@ int janet_verify(JanetFuncDef *def) {
|
||||
int32_t maxslot = def->arity + vargs;
|
||||
int32_t sc = def->slotcount;
|
||||
|
||||
/* Yes, this skips checks. Only for loading from core image */
|
||||
if (def->flags & JANET_FUNCDEF_FLAG_LAZY_BYTECODE) return 0;
|
||||
|
||||
if (def->environments_length > 256) return 15;
|
||||
if (def->bytecode_length == 0) return 1;
|
||||
|
||||
|
||||
+1
-1
@@ -1384,7 +1384,7 @@ JanetTable *janet_core_env(JanetTable *replacements) {
|
||||
Janet marsh_out = janet_unmarshal(
|
||||
janet_core_image,
|
||||
janet_core_image_size,
|
||||
0,
|
||||
JANET_MARSHAL_LAZY_BYTECODE,
|
||||
dict,
|
||||
NULL);
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
/* Add a break point to a function */
|
||||
void janet_debug_break(JanetFuncDef *def, int32_t pc) {
|
||||
janet_def_lazy_init(def);
|
||||
if (pc >= def->bytecode_length || pc < 0)
|
||||
janet_panic("invalid bytecode offset");
|
||||
def->bytecode[pc] |= 0x80;
|
||||
@@ -42,6 +43,7 @@ void janet_debug_break(JanetFuncDef *def, int32_t pc) {
|
||||
|
||||
/* Remove a break point from a function */
|
||||
void janet_debug_unbreak(JanetFuncDef *def, int32_t pc) {
|
||||
janet_def_lazy_init(def);
|
||||
if (pc >= def->bytecode_length || pc < 0)
|
||||
janet_panic("invalid bytecode offset");
|
||||
def->bytecode[pc] &= ~((uint32_t)0x80);
|
||||
@@ -67,6 +69,7 @@ void janet_debug_find(
|
||||
if (def->sourcemap &&
|
||||
def->source &&
|
||||
!janet_string_compare(source, def->source)) {
|
||||
janet_def_lazy_init(def);
|
||||
/* Correct source file, check mappings. The chosen
|
||||
* pc index is the instruction closest to the given line column, but
|
||||
* not after. */
|
||||
|
||||
@@ -217,6 +217,7 @@ int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func) {
|
||||
}
|
||||
|
||||
/* Set up the next frame */
|
||||
janet_def_lazy_init(func->def);
|
||||
fiber->frame = nextframe;
|
||||
fiber->stacktop = fiber->stackstart = nextstacktop;
|
||||
newframe = janet_fiber_frame(fiber);
|
||||
@@ -387,6 +388,7 @@ int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func) {
|
||||
fiber->stacktop = fiber->stackstart = nextstacktop;
|
||||
|
||||
/* Set frame stuff */
|
||||
janet_def_lazy_init(func->def);
|
||||
janet_fiber_frame(fiber)->func = func;
|
||||
janet_fiber_frame(fiber)->pc = func->def->bytecode;
|
||||
janet_fiber_frame(fiber)->flags |= JANET_STACKFRAME_TAILCALL;
|
||||
|
||||
+6
-2
@@ -368,8 +368,12 @@ static void janet_deinit_block(JanetGCObject *mem) {
|
||||
janet_free(def->defs);
|
||||
janet_free(def->environments);
|
||||
janet_free(def->constants);
|
||||
janet_free(def->bytecode);
|
||||
janet_free(def->sourcemap);
|
||||
if (!(def->flags & JANET_FUNCDEF_FLAG_LAZY_BYTECODE)) {
|
||||
janet_free(def->bytecode);
|
||||
}
|
||||
if (!(def->flags & JANET_FUNCDEF_FLAG_LAZY_SOURCEMAP)) {
|
||||
janet_free(def->sourcemap);
|
||||
}
|
||||
janet_free(def->closure_bitset);
|
||||
janet_free(def->symbolmap);
|
||||
}
|
||||
|
||||
+83
-11
@@ -256,6 +256,64 @@ static void janet_marshal_u32s(MarshalState *st, const uint32_t *u32s, int32_t n
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t unsafe_readint(const uint8_t **atdata) {
|
||||
const uint8_t *data = *atdata;
|
||||
int32_t ret;
|
||||
if (*data < 128) {
|
||||
ret = *data++;
|
||||
} else if (*data < 192) {
|
||||
uint32_t uret = ((data[0] & 0x3F) << 8) + data[1];
|
||||
/* Sign extend 18 MSBs */
|
||||
uret |= (uret >> 13) ? 0xFFFFC000 : 0;
|
||||
ret = (int32_t)uret;
|
||||
data += 2;
|
||||
} else if (*data == LB_INTEGER) {
|
||||
uint32_t ui = ((uint32_t)(data[1]) << 24) |
|
||||
((uint32_t)(data[2]) << 16) |
|
||||
((uint32_t)(data[3]) << 8) |
|
||||
(uint32_t)(data[4]);
|
||||
ret = (int32_t)ui;
|
||||
data += 5;
|
||||
} else {
|
||||
janet_assert(0, "bad int");
|
||||
ret = 0;
|
||||
}
|
||||
*atdata = data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Lazy initialization of function defs from ROM */
|
||||
void janet_def_lazy_init(JanetFuncDef *def) {
|
||||
if (def->flags & JANET_FUNCDEF_FLAG_LAZY_BYTECODE) {
|
||||
def->flags &= ~((uint32_t)JANET_FUNCDEF_FLAG_LAZY_BYTECODE);
|
||||
uint8_t *data = (uint8_t *) def->bytecode;
|
||||
int32_t len = def->bytecode_length;
|
||||
def->bytecode = array_allocate(sizeof(uint32_t), len);
|
||||
for (int32_t i = 0; i < len; i++) {
|
||||
int s = sizeof(uint32_t);
|
||||
/* Handle endianess */
|
||||
def->bytecode[i] =
|
||||
(uint32_t)(data[s * i]) |
|
||||
((uint32_t)(data[s * i + 1]) << 8) |
|
||||
((uint32_t)(data[s * i + 2]) << 16) |
|
||||
((uint32_t)(data[s * i + 3]) << 24);
|
||||
}
|
||||
}
|
||||
if (def->flags & JANET_FUNCDEF_FLAG_LAZY_SOURCEMAP) {
|
||||
def->flags &= ~((uint32_t)JANET_FUNCDEF_FLAG_LAZY_SOURCEMAP);
|
||||
def->flags |= JANET_FUNCDEF_FLAG_HASSOURCEMAP;
|
||||
const uint8_t *data = (const uint8_t *) def->sourcemap;
|
||||
int32_t len = def->bytecode_length;
|
||||
def->sourcemap = array_allocate(sizeof(JanetSourceMapping), len);
|
||||
int32_t current = 0;
|
||||
for (int32_t i = 0; i < len; i++) {
|
||||
current += unsafe_readint(&data);
|
||||
def->sourcemap[i].line = current;
|
||||
def->sourcemap[i].column = unsafe_readint(&data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Marshal a function def */
|
||||
static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
|
||||
MARSH_STACKCHECK;
|
||||
@@ -269,6 +327,7 @@ static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
|
||||
/* Add to lookup */
|
||||
janet_v_push(st->seen_defs, def);
|
||||
|
||||
janet_def_lazy_init(def);
|
||||
pushint(st, def->flags);
|
||||
pushint(st, def->slotcount);
|
||||
pushint(st, def->arity);
|
||||
@@ -1001,7 +1060,13 @@ static const uint8_t *unmarshal_one_def(
|
||||
if (!def->bytecode) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
data = janet_unmarshal_u32s(st, data, def->bytecode, bytecode_length);
|
||||
if (flags & JANET_MARSHAL_LAZY_BYTECODE) {
|
||||
def->flags |= JANET_FUNCDEF_FLAG_LAZY_BYTECODE;
|
||||
def->bytecode = (uint32_t *) data;
|
||||
data += bytecode_length * sizeof(uint32_t);
|
||||
} else {
|
||||
data = janet_unmarshal_u32s(st, data, def->bytecode, bytecode_length);
|
||||
}
|
||||
def->bytecode_length = bytecode_length;
|
||||
|
||||
/* Unmarshal environments */
|
||||
@@ -1034,15 +1099,22 @@ static const uint8_t *unmarshal_one_def(
|
||||
|
||||
/* Unmarshal source maps if needed */
|
||||
if (def->flags & JANET_FUNCDEF_FLAG_HASSOURCEMAP) {
|
||||
int32_t current = 0;
|
||||
def->sourcemap = array_allocate(sizeof(JanetSourceMapping), bytecode_length);
|
||||
if (!def->sourcemap) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
for (int32_t i = 0; i < bytecode_length; i++) {
|
||||
current += readint(st, &data);
|
||||
def->sourcemap[i].line = current;
|
||||
def->sourcemap[i].column = readint(st, &data);
|
||||
if (flags & JANET_MARSHAL_LAZY_BYTECODE) {
|
||||
def->flags &= ~((uint32_t)JANET_FUNCDEF_FLAG_HASSOURCEMAP);
|
||||
def->flags |= JANET_FUNCDEF_FLAG_LAZY_SOURCEMAP;
|
||||
def->sourcemap = (JanetSourceMapping *) data;
|
||||
for (int32_t i = 0; i < bytecode_length; i++) {
|
||||
readint(st, &data);
|
||||
readint(st, &data);
|
||||
}
|
||||
} else {
|
||||
int32_t current = 0;
|
||||
def->sourcemap = array_allocate(sizeof(JanetSourceMapping), bytecode_length);
|
||||
for (int32_t i = 0; i < bytecode_length; i++) {
|
||||
current += readint(st, &data);
|
||||
def->sourcemap[i].line = current;
|
||||
def->sourcemap[i].column = readint(st, &data);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
def->sourcemap = NULL;
|
||||
@@ -1484,7 +1556,7 @@ static const uint8_t *unmarshal_one(
|
||||
/* Tuple */
|
||||
Janet *tup = janet_tuple_begin(len);
|
||||
int32_t flag = readint(st, &data);
|
||||
janet_tuple_flag(tup) |= (int32_t) (((uint32_t) flag) << 16); /* Avoid left shift of negative value */
|
||||
janet_tuple_flag(tup) |= (int32_t)(((uint32_t) flag) << 16); /* Avoid left shift of negative value */
|
||||
for (int32_t i = 0; i < len; i++) {
|
||||
data = unmarshal_one(st, data, tup + i, flags + 1);
|
||||
}
|
||||
|
||||
+3
-3
@@ -734,10 +734,10 @@ static JanetSlot janetc_if(JanetFopts opts, int32_t argn, const Janet *argv) {
|
||||
labeld = janet_v_count(c->buffer);
|
||||
if (labeljr < labeld) {
|
||||
check_16bit_jump(c, labeljr, labelr);
|
||||
c->buffer[labeljr] |= (uint32_t) (labelr - labeljr) << 16;
|
||||
c->buffer[labeljr] |= (uint32_t)(labelr - labeljr) << 16;
|
||||
if (!tail && labeljd < labeld) {
|
||||
check_24bit_jump(c, labeljd, labeld);
|
||||
c->buffer[labeljd] |= (uint32_t) (labeld - labeljd) << 8;
|
||||
c->buffer[labeljd] |= (uint32_t)(labeld - labeljd) << 8;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -991,7 +991,7 @@ static JanetSlot janetc_while(JanetFopts opts, int32_t argn, const Janet *argv)
|
||||
for (int32_t i = labelwt; i < labeld; i++) {
|
||||
if (c->buffer[i] == (0x80 | JOP_JUMP)) {
|
||||
check_24bit_jump(c, i, labeld);
|
||||
c->buffer[i] = JOP_JUMP | ((uint32_t) (labeld - i) << 8);
|
||||
c->buffer[i] = JOP_JUMP | ((uint32_t)(labeld - i) << 8);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@
|
||||
|
||||
/* Lookup table for getting values of characters when parsing numbers. Handles
|
||||
* digits 0-9 and a-z (and A-Z). A-Z have values of 10 to 35. */
|
||||
static uint8_t digit_lookup[128] = {
|
||||
static const uint8_t digit_lookup[128] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
|
||||
+1
-1
@@ -584,7 +584,7 @@ static void janet_check_pointer_align(void *p) {
|
||||
uintptr_t u;
|
||||
} un;
|
||||
un.p = p;
|
||||
janet_assert(!(un.u & (uintptr_t) ((1 << JANET_NANBOX_64_POINTER_SHIFT) - 1)),
|
||||
janet_assert(!(un.u & (uintptr_t)((1 << JANET_NANBOX_64_POINTER_SHIFT) - 1)),
|
||||
"unaligned pointer wrap - cfunction pointers and abstract types must be aligned with this nanboxing configuration.");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -99,6 +99,8 @@ void janet_def_addflags(JanetFuncDef *def);
|
||||
|
||||
void janet_buffer_dtostr(JanetBuffer *buffer, double x);
|
||||
|
||||
void janet_def_lazy_init(JanetFuncDef *def);
|
||||
|
||||
const char *janet_strerror(int e);
|
||||
|
||||
const void *janet_strbinsearch(
|
||||
|
||||
@@ -1049,6 +1049,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
|
||||
}
|
||||
if (janet_checktype(callee, JANET_FUNCTION)) {
|
||||
func = janet_unwrap_function(callee);
|
||||
janet_def_lazy_init(func->def);
|
||||
if (func->gc.flags & JANET_FUNCFLAG_TRACE) {
|
||||
vm_do_trace(func, fiber->stacktop - fiber->stackstart, fiber->data + fiber->stackstart);
|
||||
}
|
||||
@@ -1089,6 +1090,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) {
|
||||
}
|
||||
if (janet_checktype(callee, JANET_FUNCTION)) {
|
||||
func = janet_unwrap_function(callee);
|
||||
janet_def_lazy_init(func->def);
|
||||
if (func->gc.flags & JANET_FUNCFLAG_TRACE) {
|
||||
vm_do_trace(func, fiber->stacktop - fiber->stackstart, fiber->data + fiber->stackstart);
|
||||
}
|
||||
|
||||
@@ -1105,6 +1105,8 @@ struct JanetAbstractHead {
|
||||
#define JANET_FUNCDEF_FLAG_STRUCTARG 0x1000000
|
||||
#define JANET_FUNCDEF_FLAG_HASCLOBITSET 0x2000000
|
||||
#define JANET_FUNCDEF_FLAG_NAMEDARGS 0x4000000
|
||||
#define JANET_FUNCDEF_FLAG_LAZY_BYTECODE 0x8000000
|
||||
#define JANET_FUNCDEF_FLAG_LAZY_SOURCEMAP 0x10000000
|
||||
#define JANET_FUNCDEF_FLAG_TAG 0xFFFF
|
||||
|
||||
/* Source mapping structure for a bytecode instruction */
|
||||
@@ -1909,6 +1911,7 @@ JANET_API JanetModule janet_native(const char *name, JanetString *error);
|
||||
/* Marshaling */
|
||||
#define JANET_MARSHAL_UNSAFE 0x20000
|
||||
#define JANET_MARSHAL_NO_CYCLES 0x40000
|
||||
#define JANET_MARSHAL_LAZY_BYTECODE 0x80000
|
||||
|
||||
JANET_API void janet_marshal(
|
||||
JanetBuffer *buf,
|
||||
|
||||
Reference in New Issue
Block a user