From fed0c2ad3414da497cdf73987d3dd1ddd1b62b5e Mon Sep 17 00:00:00 2001 From: Sky Johnson Date: Thu, 27 Mar 2025 21:41:06 -0500 Subject: [PATCH] optimize bytecode --- bytecode.go | 79 ++++++++++++++++++----------------------------------- 1 file changed, 27 insertions(+), 52 deletions(-) diff --git a/bytecode.go b/bytecode.go index de296bb..3c8f870 100644 --- a/bytecode.go +++ b/bytecode.go @@ -12,7 +12,7 @@ typedef struct { const char *name; } BytecodeReader; -static const char *bytecode_reader(lua_State *L, void *ud, size_t *size) { +const char *bytecode_reader(lua_State *L, void *ud, size_t *size) { BytecodeReader *r = (BytecodeReader *)ud; (void)L; // unused if (r->size == 0) return NULL; @@ -21,45 +21,23 @@ static const char *bytecode_reader(lua_State *L, void *ud, size_t *size) { return (const char *)r->buf; } -static int load_bytecode(lua_State *L, const unsigned char *buf, size_t len, const char *name) { +int load_bytecode(lua_State *L, const unsigned char *buf, size_t len, const char *name) { BytecodeReader reader = {buf, len, name}; return lua_load(L, bytecode_reader, &reader, name); } -typedef struct { - unsigned char *buf; - size_t len; - size_t capacity; -} BytecodeWriter; +// Direct bytecode dumping without intermediate buffer - more efficient +int direct_bytecode_writer(lua_State *L, const void *p, size_t sz, void *ud) { + void **data = (void **)ud; + size_t current_size = (size_t)data[1]; + void *newbuf = realloc(data[0], current_size + sz); + if (newbuf == NULL) return 1; -static int bytecode_writer(lua_State *L, const void *p, size_t sz, void *ud) { - BytecodeWriter *w = (BytecodeWriter *)ud; - unsigned char *newbuf; - (void)L; // unused - - // Check if we need to reallocate - if (w->len + sz > w->capacity) { - size_t new_capacity = w->capacity * 2; - if (new_capacity < w->len + sz) { - new_capacity = w->len + sz; - } - - newbuf = (unsigned char *)realloc(w->buf, new_capacity); - if (newbuf == NULL) return 1; - - w->buf = newbuf; - w->capacity = new_capacity; - } - - memcpy(w->buf + w->len, p, sz); - w->len += sz; + memcpy((unsigned char*)newbuf + current_size, p, sz); + data[0] = newbuf; + data[1] = (void*)(current_size + sz); return 0; } - -// Wrapper function that calls lua_dump with bytecode_writer -static int dump_lua_function(lua_State *L, BytecodeWriter *w) { - return lua_dump(L, bytecode_writer, w); -} */ import "C" import ( @@ -73,31 +51,23 @@ func (s *State) CompileBytecode(code string, name string) ([]byte, error) { return nil, fmt.Errorf("failed to load string: %w", err) } - // Set up writer with initial capacity - var writer C.BytecodeWriter - writer.buf = nil - writer.len = 0 - writer.capacity = 0 - - // Initial allocation with a reasonable size - const initialSize = 4096 - writer.buf = (*C.uchar)(C.malloc(initialSize)) - if writer.buf == nil { - s.Pop(1) // Remove the loaded function - return nil, fmt.Errorf("failed to allocate memory for bytecode") - } - writer.capacity = initialSize + // Use a simpler direct writer with just two pointers + data := [2]unsafe.Pointer{nil, nil} // Dump the function to bytecode err := s.safeCall(func() C.int { - return C.dump_lua_function(s.L, (*C.BytecodeWriter)(unsafe.Pointer(&writer))) + return C.lua_dump(s.L, (*[0]byte)(unsafe.Pointer(C.direct_bytecode_writer)), unsafe.Pointer(&data)) }) - // Copy bytecode to Go slice regardless of the result - bytecode := C.GoBytes(unsafe.Pointer(writer.buf), C.int(writer.len)) + // Get result + var bytecode []byte + if data[0] != nil { + // Create Go slice that references the C memory + length := uintptr(data[1]) + bytecode = C.GoBytes(data[0], C.int(length)) + C.free(data[0]) + } - // Clean up - C.free(unsafe.Pointer(writer.buf)) s.Pop(1) // Remove the function from stack if err != nil { @@ -164,6 +134,11 @@ func (s *State) LoadAndRunBytecodeWithResults(bytecode []byte, name string, nres // CompileAndRun compiles and immediately executes Lua code func (s *State) CompileAndRun(code string, name string) error { + // Skip bytecode step for small scripts - direct execution is faster + if len(code) < 1024 { + return s.DoString(code) + } + bytecode, err := s.CompileBytecode(code, name) if err != nil { return fmt.Errorf("compile error: %w", err)