Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,7 @@ type Option struct {
MemoryLimit int // Memory usage limit
MaxExecutionTime int // Execution timeout
GCThreshold int // GC trigger threshold
CacheDir string // Compilation cache directory
}
```

Expand Down
1 change: 1 addition & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type Option struct {
// because every operation must check the done context, which introduces additional overhead.
CloseOnContextDone bool
DisableBuildCache bool
CacheDir string
MemoryLimit int
MaxStackSize int
MaxExecutionTime int
Expand Down
10 changes: 9 additions & 1 deletion runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func createGlobalCompiledModule(
ctx context.Context,
closeOnContextDone bool,
disableBuildCache bool,
cacheDir string,
quickjsWasmBytes ...[]byte,
) (err error) {
// Protect global compilation state with mutex
Expand All @@ -58,7 +59,13 @@ func createGlobalCompiledModule(

// Check if we need to compile or recompile
if compiledQJSModule == nil || cachedBytesHash != currentHash || disableBuildCache {
cache := wazero.NewCompilationCache()
var cache wazero.CompilationCache
if cacheDir == "" {
cache = wazero.NewCompilationCache()
} else if cache, err = wazero.NewCompilationCacheWithDir(cacheDir); err != nil {
return fmt.Errorf("failed to create compilation cache with dir %s: %w", cacheDir, err)
}

cachedRuntimeConfig = wazero.
NewRuntimeConfig().
WithCompilationCache(cache).
Expand Down Expand Up @@ -96,6 +103,7 @@ func New(options ...Option) (runtime *Runtime, err error) {
option.Context,
option.CloseOnContextDone,
option.DisableBuildCache,
option.CacheDir,
option.QuickJSWasmBytes,
); err != nil {
return nil, fmt.Errorf("failed to create global compiled module: %w", err)
Expand Down
34 changes: 34 additions & 0 deletions runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package qjs_test
import (
"context"
"fmt"
"os"
"sync"
"testing"
"time"
Expand Down Expand Up @@ -255,6 +256,39 @@ func TestRuntime(t *testing.T) {
require.NoError(t, err, "Normal runtime creation should still work after invalid attempt")
defer rt2.Close()
})

t.Run("CacheDirOption", func(t *testing.T) {
cacheDir := t.TempDir()
rt1, err := qjs.New(qjs.Option{CacheDir: cacheDir, DisableBuildCache: true})
require.NoError(t, err)

val, err := rt1.Eval("test.js", qjs.Code("21 + 21"))
require.NoError(t, err)
assert.Equal(t, int32(42), val.Int32())
val.Free()

rt1.Close()
entries, err := os.ReadDir(cacheDir)
require.NoError(t, err)
assert.NotEmpty(t, entries, "Cache directory should not be empty")
})

t.Run("CacheDirWithEmptyString", func(t *testing.T) {
rt, err := qjs.New(qjs.Option{CacheDir: "", DisableBuildCache: true})
require.NoError(t, err)
defer rt.Close()

val, err := rt.Eval("test.js", qjs.Code("2 * 21"))
require.NoError(t, err)
assert.Equal(t, int32(42), val.Int32())
val.Free()
})

t.Run("CacheDirWithInvalidPath", func(t *testing.T) {
_, err := qjs.New(qjs.Option{CacheDir: "/invalid/path/that/does/not/exist", DisableBuildCache: true})
require.Error(t, err)
assert.Contains(t, err.Error(), "failed to create compilation cache")
})
}

// Concurrent Runtime Usage Tests
Expand Down
Loading