diff --git a/wrapper.go b/wrapper.go index f5b2add..ea2247f 100644 --- a/wrapper.go +++ b/wrapper.go @@ -11,7 +11,7 @@ package luajit #include #include -// Helper to simplify some common operations +// Optimized helpers for common operations static int get_abs_index(lua_State *L, int idx) { if (idx > 0 || idx <= LUA_REGISTRYINDEX) return idx; return lua_gettop(L) + idx + 1; @@ -39,9 +39,17 @@ import "C" import ( "fmt" "strings" + "sync" "unsafe" ) +// Type pool for common objects to reduce GC pressure +var stringBufferPool = sync.Pool{ + New: func() any { + return new(strings.Builder) + }, +} + // State represents a Lua state type State struct { L *C.lua_State @@ -78,7 +86,7 @@ func (s *State) SetTop(index int) { C.lua_settop(s.L, C.int(index)) } -// PushValue pushes a copy of the value at the given index onto the stack +// PushCopy pushes a copy of the value at the given index onto the stack func (s *State) PushCopy(index int) { C.lua_pushvalue(s.L, C.int(index)) } @@ -183,9 +191,22 @@ func (s *State) PushNumber(n float64) { // PushString pushes a string value onto the stack func (s *State) PushString(str string) { - cstr := C.CString(str) - defer C.free(unsafe.Pointer(cstr)) - C.lua_pushlstring(s.L, cstr, C.size_t(len(str))) + // Use direct C string for short strings (avoid allocations) + if len(str) < 128 { + cstr := C.CString(str) + defer C.free(unsafe.Pointer(cstr)) + C.lua_pushlstring(s.L, cstr, C.size_t(len(str))) + return + } + + // For longer strings, avoid double copy by using unsafe pointer + header := (*struct { + p unsafe.Pointer + len int + cap int + })(unsafe.Pointer(&str)) + + C.lua_pushlstring(s.L, (*C.char)(header.p), C.size_t(len(str))) } // Table operations @@ -406,13 +427,15 @@ func (s *State) ExecuteWithResult(code string) (any, error) { // SetPackagePath sets the Lua package.path func (s *State) SetPackagePath(path string) error { path = strings.ReplaceAll(path, "\\", "/") // Convert Windows paths - return s.DoString(fmt.Sprintf(`package.path = %q`, path)) + code := fmt.Sprintf(`package.path = %q`, path) + return s.DoString(code) } // AddPackagePath adds a path to package.path func (s *State) AddPackagePath(path string) error { path = strings.ReplaceAll(path, "\\", "/") // Convert Windows paths - return s.DoString(fmt.Sprintf(`package.path = package.path .. ";%s"`, path)) + code := fmt.Sprintf(`package.path = package.path .. ";%s"`, path) + return s.DoString(code) } // Helper functions