Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable explicit destruction of all resources #209

Merged
merged 2 commits into from
Feb 15, 2024
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
12 changes: 12 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import unittest
from contextlib import closing

from wasmtime import *

Expand Down Expand Up @@ -34,3 +35,14 @@ def test_smoke(self):
config.consume_fuel = True
config.wasm_relaxed_simd = True
config.wasm_relaxed_simd_deterministic = True

with closing(config) as config:
pass

config.close()

with self.assertRaises(ValueError):
Engine(config)

with self.assertRaises(ValueError):
config.cache = True
2 changes: 1 addition & 1 deletion tests/test_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ def test_errors(self):
Engine(3) # type: ignore
config = Config()
Engine(config)
with self.assertRaises(WasmtimeError):
with self.assertRaises(ValueError):
Engine(config)
9 changes: 9 additions & 0 deletions tests/test_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ def test_smoke(self):
Store()
Store(Engine())

with Store() as store:
pass

store = Store()
store.close()
store.close()
with self.assertRaises(ValueError):
store.set_epoch_deadline(1)

def test_errors(self):
with self.assertRaises(TypeError):
Store(3) # type: ignore
Expand Down
1 change: 1 addition & 0 deletions wasmtime/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
libraries are intended to be quite similar.
"""

from ._managed import Managed
from ._error import WasmtimeError, ExitTrap
from ._config import Config
from ._engine import Engine
Expand Down
61 changes: 29 additions & 32 deletions wasmtime/_config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from . import _ffi as ffi
from ctypes import *
import ctypes
from wasmtime import WasmtimeError
from wasmtime import WasmtimeError, Managed
import typing


Expand All @@ -13,18 +13,19 @@ def setter_property(fset: typing.Callable) -> property:
return prop


class Config:
class Config(Managed["ctypes._Pointer[ffi.wasm_config_t]"]):
"""
Global configuration, used to create an `Engine`.

A `Config` houses a number of configuration options which tweaks how wasm
code is compiled or generated.
"""

_ptr: "ctypes._Pointer[ffi.wasm_config_t]"

def __init__(self) -> None:
self._ptr = ffi.wasm_config_new()
self._set_ptr(ffi.wasm_config_new())

def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_config_t]") -> None:
ffi.wasm_config_delete(ptr)

@setter_property
def debug_info(self, enable: bool) -> None:
Expand All @@ -35,7 +36,7 @@ def debug_info(self, enable: bool) -> None:

if not isinstance(enable, bool):
raise TypeError('expected a bool')
ffi.wasmtime_config_debug_info_set(self._ptr, enable)
ffi.wasmtime_config_debug_info_set(self.ptr(), enable)

@setter_property
def wasm_threads(self, enable: bool) -> None:
Expand All @@ -47,7 +48,7 @@ def wasm_threads(self, enable: bool) -> None:

if not isinstance(enable, bool):
raise TypeError('expected a bool')
ffi.wasmtime_config_wasm_threads_set(self._ptr, enable)
ffi.wasmtime_config_wasm_threads_set(self.ptr(), enable)

@setter_property
def wasm_reference_types(self, enable: bool) -> None:
Expand All @@ -59,7 +60,7 @@ def wasm_reference_types(self, enable: bool) -> None:

if not isinstance(enable, bool):
raise TypeError('expected a bool')
ffi.wasmtime_config_wasm_reference_types_set(self._ptr, enable)
ffi.wasmtime_config_wasm_reference_types_set(self.ptr(), enable)

@setter_property
def wasm_simd(self, enable: bool) -> None:
Expand All @@ -71,7 +72,7 @@ def wasm_simd(self, enable: bool) -> None:

if not isinstance(enable, bool):
raise TypeError('expected a bool')
ffi.wasmtime_config_wasm_simd_set(self._ptr, enable)
ffi.wasmtime_config_wasm_simd_set(self.ptr(), enable)

@setter_property
def wasm_bulk_memory(self, enable: bool) -> None:
Expand All @@ -83,7 +84,7 @@ def wasm_bulk_memory(self, enable: bool) -> None:

if not isinstance(enable, bool):
raise TypeError('expected a bool')
ffi.wasmtime_config_wasm_bulk_memory_set(self._ptr, enable)
ffi.wasmtime_config_wasm_bulk_memory_set(self.ptr(), enable)

@setter_property
def wasm_multi_value(self, enable: bool) -> None:
Expand All @@ -95,7 +96,7 @@ def wasm_multi_value(self, enable: bool) -> None:

if not isinstance(enable, bool):
raise TypeError('expected a bool')
ffi.wasmtime_config_wasm_multi_value_set(self._ptr, enable)
ffi.wasmtime_config_wasm_multi_value_set(self.ptr(), enable)

@setter_property
def wasm_multi_memory(self, enable: bool) -> None:
Expand All @@ -107,7 +108,7 @@ def wasm_multi_memory(self, enable: bool) -> None:

if not isinstance(enable, bool):
raise TypeError('expected a bool')
ffi.wasmtime_config_wasm_multi_memory_set(self._ptr, enable)
ffi.wasmtime_config_wasm_multi_memory_set(self.ptr(), enable)

@setter_property
def wasm_memory64(self, enable: bool) -> None:
Expand All @@ -119,7 +120,7 @@ def wasm_memory64(self, enable: bool) -> None:

if not isinstance(enable, bool):
raise TypeError('expected a bool')
ffi.wasmtime_config_wasm_memory64_set(self._ptr, enable)
ffi.wasmtime_config_wasm_memory64_set(self.ptr(), enable)

@setter_property
def wasm_relaxed_simd(self, enable: bool) -> None:
Expand All @@ -131,7 +132,7 @@ def wasm_relaxed_simd(self, enable: bool) -> None:

if not isinstance(enable, bool):
raise TypeError('expected a bool')
ffi.wasmtime_config_wasm_relaxed_simd_set(self._ptr, enable)
ffi.wasmtime_config_wasm_relaxed_simd_set(self.ptr(), enable)

@setter_property
def wasm_relaxed_simd_deterministic(self, enable: bool) -> None:
Expand All @@ -145,7 +146,7 @@ def wasm_relaxed_simd_deterministic(self, enable: bool) -> None:

if not isinstance(enable, bool):
raise TypeError('expected a bool')
ffi.wasmtime_config_wasm_relaxed_simd_deterministic_set(self._ptr, enable)
ffi.wasmtime_config_wasm_relaxed_simd_deterministic_set(self.ptr(), enable)

@setter_property
def strategy(self, strategy: str) -> None:
Expand All @@ -159,35 +160,35 @@ def strategy(self, strategy: str) -> None:
"""

if strategy == "auto":
ffi.wasmtime_config_strategy_set(self._ptr, 0)
ffi.wasmtime_config_strategy_set(self.ptr(), 0)
elif strategy == "cranelift":
ffi.wasmtime_config_strategy_set(self._ptr, 1)
ffi.wasmtime_config_strategy_set(self.ptr(), 1)
else:
raise WasmtimeError("unknown strategy: " + str(strategy))

@setter_property
def cranelift_debug_verifier(self, enable: bool) -> None:
if not isinstance(enable, bool):
raise TypeError('expected a bool')
ffi.wasmtime_config_cranelift_debug_verifier_set(self._ptr, enable)
ffi.wasmtime_config_cranelift_debug_verifier_set(self.ptr(), enable)

@setter_property
def cranelift_opt_level(self, opt_level: str) -> None:
if opt_level == "none":
ffi.wasmtime_config_cranelift_opt_level_set(self._ptr, 0)
ffi.wasmtime_config_cranelift_opt_level_set(self.ptr(), 0)
elif opt_level == "speed":
ffi.wasmtime_config_cranelift_opt_level_set(self._ptr, 1)
ffi.wasmtime_config_cranelift_opt_level_set(self.ptr(), 1)
elif opt_level == "speed_and_size":
ffi.wasmtime_config_cranelift_opt_level_set(self._ptr, 2)
ffi.wasmtime_config_cranelift_opt_level_set(self.ptr(), 2)
else:
raise WasmtimeError("unknown opt level: " + str(opt_level))

@setter_property
def profiler(self, profiler: str) -> None:
if profiler == "none":
ffi.wasmtime_config_profiler_set(self._ptr, 0)
ffi.wasmtime_config_profiler_set(self.ptr(), 0)
elif profiler == "jitdump":
ffi.wasmtime_config_profiler_set(self._ptr, 1)
ffi.wasmtime_config_profiler_set(self.ptr(), 1)
else:
raise WasmtimeError("unknown profiler: " + str(profiler))

Expand All @@ -207,9 +208,9 @@ def cache(self, enabled: typing.Union[bool, str]) -> None:
if isinstance(enabled, bool):
if not enabled:
raise WasmtimeError("caching cannot be explicitly disabled")
error = ffi.wasmtime_config_cache_config_load(self._ptr, None)
error = ffi.wasmtime_config_cache_config_load(self.ptr(), None)
elif isinstance(enabled, str):
error = ffi.wasmtime_config_cache_config_load(self._ptr,
error = ffi.wasmtime_config_cache_config_load(self.ptr(),
c_char_p(enabled.encode('utf-8')))
else:
raise TypeError("expected string or bool")
Expand All @@ -227,7 +228,7 @@ def epoch_interruption(self, enabled: bool) -> None:
val = 1
else:
val = 0
ffi.wasmtime_config_epoch_interruption_set(self._ptr, val)
ffi.wasmtime_config_epoch_interruption_set(self.ptr(), val)

@setter_property
def consume_fuel(self, instances: bool) -> None:
Expand All @@ -240,7 +241,7 @@ def consume_fuel(self, instances: bool) -> None:
"""
if not isinstance(instances, bool):
raise TypeError('expected an bool')
ffi.wasmtime_config_consume_fuel_set(self._ptr, instances)
ffi.wasmtime_config_consume_fuel_set(self.ptr(), instances)

@setter_property
def parallel_compilation(self, enable: bool) -> None:
Expand All @@ -252,8 +253,4 @@ def parallel_compilation(self, enable: bool) -> None:
"""
if not isinstance(enable, bool):
raise TypeError('expected a bool')
ffi.wasmtime_config_parallel_compilation_set(self._ptr, enable)

def __del__(self) -> None:
if hasattr(self, '_ptr'):
ffi.wasm_config_delete(self._ptr)
ffi.wasmtime_config_parallel_compilation_set(self.ptr(), enable)
23 changes: 9 additions & 14 deletions wasmtime/_engine.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
from . import _ffi as ffi
from wasmtime import Config, WasmtimeError
from wasmtime import Config, WasmtimeError, Managed
from typing import Optional
import ctypes


class Engine:
_ptr: "ctypes._Pointer[ffi.wasm_engine_t]"
class Engine(Managed["ctypes._Pointer[ffi.wasm_engine_t]"]):

def __init__(self, config: Optional[Config] = None):
if config is None:
self._ptr = ffi.wasm_engine_new()
self._set_ptr(ffi.wasm_engine_new())
elif not isinstance(config, Config):
raise TypeError("expected Config")
elif not hasattr(config, '_ptr'):
raise WasmtimeError("Config already used")
else:
ptr = config._ptr
delattr(config, '_ptr')
self._ptr = ffi.wasm_engine_new_with_config(ptr)
ptr = config._consume()
self._set_ptr(ffi.wasm_engine_new_with_config(ptr))

def increment_epoch(self) -> None:
ffi.wasmtime_engine_increment_epoch(self._ptr)
def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_engine_t]") -> None:
ffi.wasm_engine_delete(ptr)

def __del__(self) -> None:
if hasattr(self, '_ptr'):
ffi.wasm_engine_delete(self._ptr)
def increment_epoch(self) -> None:
ffi.wasmtime_engine_increment_epoch(self.ptr())
30 changes: 14 additions & 16 deletions wasmtime/_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@
from . import _ffi as ffi
import ctypes
from typing import Optional
from wasmtime import Managed


class WasmtimeError(Exception):
_ptr: "Optional[ctypes._Pointer[ffi.wasmtime_error_t]]"
_message: Optional[str]
class WasmtimeError(Exception, Managed["ctypes._Pointer[ffi.wasmtime_error_t]"]):
__message: Optional[str]

def __init__(self, message: str):
self._message = message
self._ptr = None
self.__message = message

def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_error_t]") -> None:
ffi.wasmtime_error_delete(ptr)

@classmethod
def _from_ptr(cls, ptr: "ctypes._Pointer") -> 'WasmtimeError':
Expand All @@ -21,29 +23,25 @@ def _from_ptr(cls, ptr: "ctypes._Pointer") -> 'WasmtimeError':
exit_code = c_int(0)
if ffi.wasmtime_error_exit_status(ptr, byref(exit_code)):
exit_trap: ExitTrap = ExitTrap.__new__(ExitTrap)
exit_trap._ptr = ptr
exit_trap._message = None
exit_trap._set_ptr(ptr)
exit_trap.__message = None
exit_trap.code = exit_code.value
return exit_trap

err: WasmtimeError = cls.__new__(cls)
err._ptr = ptr
err._message = None
err._set_ptr(ptr)
err.__message = None
return err

def __str__(self) -> str:
if self._message:
return self._message
if self.__message:
return self.__message
message_vec = ffi.wasm_byte_vec_t()
ffi.wasmtime_error_message(self._ptr, byref(message_vec))
ffi.wasmtime_error_message(self.ptr(), byref(message_vec))
message = ffi.to_str(message_vec)
ffi.wasm_byte_vec_delete(byref(message_vec))
return message

def __del__(self) -> None:
if hasattr(self, '_ptr') and self._ptr:
ffi.wasmtime_error_delete(self._ptr)


class ExitTrap(WasmtimeError):
"""
Expand Down
10 changes: 5 additions & 5 deletions wasmtime/_extern.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from . import _ffi as ffi
import ctypes
from ._exportable import AsExtern
from wasmtime import WasmtimeError
from wasmtime import WasmtimeError, Managed


def wrap_extern(ptr: ffi.wasmtime_extern_t) -> AsExtern:
Expand Down Expand Up @@ -41,9 +41,9 @@ def get_extern_ptr(item: AsExtern) -> ffi.wasmtime_extern_t:
raise TypeError("expected a Func, Global, Memory, Table, Module, or Instance")


class Extern:
class Extern(Managed["ctypes._Pointer[ffi.wasm_extern_t]"]):
def __init__(self, ptr: "ctypes._Pointer[ffi.wasm_extern_t]"):
self.ptr = ptr
self._set_ptr(ptr)

def __del__(self) -> None:
ffi.wasm_extern_delete(self.ptr)
def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_extern_t]") -> None:
ffi.wasm_extern_delete(ptr)
Loading
Loading