introduce bytecode caching, update state management to use it
This commit is contained in:
parent
e86cb55aa6
commit
a110b93f5c
93
state/bytecode.go
Normal file
93
state/bytecode.go
Normal file
@ -0,0 +1,93 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
luajit "git.sharkk.net/Sky/LuaJIT-to-Go"
|
||||
)
|
||||
|
||||
// BytecodeEntry holds compiled bytecode with metadata
|
||||
type BytecodeEntry struct {
|
||||
Bytecode []byte
|
||||
Name string
|
||||
Hash [32]byte
|
||||
}
|
||||
|
||||
// Global bytecode cache
|
||||
var (
|
||||
bytecodeCache = struct {
|
||||
sync.RWMutex
|
||||
entries map[string]*BytecodeEntry
|
||||
}{
|
||||
entries: make(map[string]*BytecodeEntry),
|
||||
}
|
||||
)
|
||||
|
||||
// CompileAndCache compiles code to bytecode and stores it globally
|
||||
func CompileAndCache(state *luajit.State, code, name string) (*BytecodeEntry, error) {
|
||||
hash := sha256.Sum256([]byte(code))
|
||||
cacheKey := fmt.Sprintf("%x", hash)
|
||||
|
||||
// Check cache first
|
||||
bytecodeCache.RLock()
|
||||
if entry, exists := bytecodeCache.entries[cacheKey]; exists {
|
||||
bytecodeCache.RUnlock()
|
||||
return entry, nil
|
||||
}
|
||||
bytecodeCache.RUnlock()
|
||||
|
||||
// Compile bytecode
|
||||
bytecode, err := state.CompileBytecode(code, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Store in cache
|
||||
entry := &BytecodeEntry{
|
||||
Bytecode: bytecode,
|
||||
Name: name,
|
||||
Hash: hash,
|
||||
}
|
||||
|
||||
bytecodeCache.Lock()
|
||||
bytecodeCache.entries[cacheKey] = entry
|
||||
bytecodeCache.Unlock()
|
||||
|
||||
return entry, nil
|
||||
}
|
||||
|
||||
// GetCached retrieves bytecode from cache by code hash
|
||||
func GetCached(code string) (*BytecodeEntry, bool) {
|
||||
hash := sha256.Sum256([]byte(code))
|
||||
cacheKey := fmt.Sprintf("%x", hash)
|
||||
|
||||
bytecodeCache.RLock()
|
||||
defer bytecodeCache.RUnlock()
|
||||
|
||||
entry, exists := bytecodeCache.entries[cacheKey]
|
||||
return entry, exists
|
||||
}
|
||||
|
||||
// ClearCache removes all cached bytecode entries
|
||||
func ClearCache() {
|
||||
bytecodeCache.Lock()
|
||||
defer bytecodeCache.Unlock()
|
||||
|
||||
bytecodeCache.entries = make(map[string]*BytecodeEntry)
|
||||
}
|
||||
|
||||
// CacheStats returns cache statistics
|
||||
func CacheStats() (int, int64) {
|
||||
bytecodeCache.RLock()
|
||||
defer bytecodeCache.RUnlock()
|
||||
|
||||
count := len(bytecodeCache.entries)
|
||||
var totalSize int64
|
||||
for _, entry := range bytecodeCache.entries {
|
||||
totalSize += int64(len(entry.Bytecode))
|
||||
}
|
||||
|
||||
return count, totalSize
|
||||
}
|
@ -159,15 +159,14 @@ func (s *State) ExecuteFile(scriptPath string) error {
|
||||
return s.ExecuteString(string(scriptContent), scriptPath)
|
||||
}
|
||||
|
||||
// ExecuteString compiles and runs Lua code
|
||||
// ExecuteString compiles and runs Lua code with bytecode caching
|
||||
func (s *State) ExecuteString(code, name string) error {
|
||||
// Use bytecode compilation for better performance
|
||||
bytecode, err := s.CompileBytecode(code, name)
|
||||
entry, err := CompileAndCache(s.State, code, name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("compilation error in '%s': %w", name, err)
|
||||
}
|
||||
|
||||
if err := s.LoadAndRunBytecode(bytecode, name); err != nil {
|
||||
if err := s.LoadAndRunBytecode(entry.Bytecode, name); err != nil {
|
||||
return fmt.Errorf("execution error in '%s': %w", name, err)
|
||||
}
|
||||
|
||||
@ -188,16 +187,21 @@ func (s *State) ExecuteFileWithResults(scriptPath string) ([]any, error) {
|
||||
return s.ExecuteStringWithResults(string(scriptContent), scriptPath)
|
||||
}
|
||||
|
||||
// ExecuteStringWithResults executes code and returns all results
|
||||
// ExecuteStringWithResults executes code and returns all results with bytecode caching
|
||||
func (s *State) ExecuteStringWithResults(code, name string) ([]any, error) {
|
||||
baseTop := s.GetTop()
|
||||
defer s.SetTop(baseTop)
|
||||
|
||||
nresults, err := s.Execute(code)
|
||||
entry, err := CompileAndCache(s.State, code, name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("compilation error in '%s': %w", name, err)
|
||||
}
|
||||
|
||||
if err := s.LoadAndRunBytecodeWithResults(entry.Bytecode, name, -1); err != nil {
|
||||
return nil, fmt.Errorf("execution error in '%s': %w", name, err)
|
||||
}
|
||||
|
||||
nresults := s.GetTop() - baseTop
|
||||
if nresults == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user