Class: Wasmtime::Engine

Inherits:
Object
  • Object
show all
Defined in:
ext/src/ruby_api/engine.rs

Overview

Represents a Wasmtime execution engine.

Examples:

Disabling parallel compilation

# Many Ruby servers use a pre-forking mechanism to allow parallel request
# processing. Unfortunately, this can causes processes to deadlock if you
# use parallel compilation to compile Wasm prior to calling
# `Process::fork`. To avoid this issue, any compilations that need to be
# done before forking need to disable the `parallel_compilation` option.

prefork_engine = Wasmtime::Engine.new(parallel_compilation: false)
wasm_module = Wasmtime::Module.new(prefork_engine, "(module)")

fork do
  # We can enable parallel compilation now that we've forked.
  engine = Wasmtime::Engine.new(parallel_compilation: true)
  store = Wasmtime::Store.new(engine)
  instance = Wasmtime::Instance.new(store, wasm_module)
  # ...
end

See Also:

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.new(config = {}) ⇒ Object

Parameters:

  • config (Hash) (defaults to: {})

    The engine's config. See the +Config+‘s Rust doc for detailed description of the different options and the defaults.

Options Hash (config):

  • :async_stack_zeroing (Boolean)

    Configures whether or not stacks used for async futures are zeroed before (re)use.

  • :debug_info (Boolean)
  • :wasm_backtrace_details (Boolean)
  • :native_unwind_info (Boolean)
  • :consume_fuel (Boolean)
  • :epoch_interruption (Boolean)
  • :max_wasm_stack (Integer)
  • :wasm_threads (Boolean)
  • :wasm_multi_memory (Boolean)
  • :wasm_memory64 (Boolean)
  • :wasm_reference_types (Boolean)
  • :wasm_exceptions (Boolean)

    Whether the WebAssembly exception-handling proposal is enabled.

  • :parallel_compilation (Boolean) — default: true

    Whether compile Wasm using multiple threads

  • :generate_address_map (Boolean)

    Configures whether compiled artifacts will contain information to map native program addresses back to the original wasm module. This configuration option is true by default. Disabling this feature can result in considerably smaller serialized modules.

  • :cranelift_opt_level (Symbol)

    One of none, speed, speed_and_size.

  • :profiler (Symbol)

    One of none, jitdump, vtune.

  • :strategy (Symbol)

    One of auto, cranelift, winch

  • :target (String)

See Also:



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'ext/src/ruby_api/engine.rs', line 91

pub fn new(args: &[Value]) -> Result<Self, Error> {
    let args = scan_args::scan_args::<(), (Option<Value>,), (), (), (), ()>(args)?;
    let (config,) = args.optional;
    let config = config.and_then(|v| if v.is_nil() { None } else { Some(v) });
    let inner = match config {
        Some(config) => {
            let config = RHash::try_convert(config).and_then(hash_to_config)?;

            EngineImpl::new(&config).map_err(|e| error!("{}", e))?
        }
        None => EngineImpl::new(&Config::default()).map_err(|e| error!("{}", e))?,
    };

    Ok(Self {
        inner,
        #[cfg(feature = "tokio")]
        timer_task: Default::default(),
    })
}

Instance Method Details

#increment_epochnil

Manually increment the engine's epoch. Note: this cannot be used from a different thread while WebAssembly is running because the Global VM lock (GVL) is not released. Using #start_epoch_interval is recommended because it sidesteps the GVL.

Returns:

  • (nil)


156
157
158
# File 'ext/src/ruby_api/engine.rs', line 156

pub fn increment_epoch(&self) {
    self.inner.increment_epoch();
}

#precompile_compatibility_keyString

If two engines have a matching #precompile_compatibility_key, then serialized modules from one engine can be deserialized by the other.

Returns:

  • (String)

    The hex formatted string that can be used to check precompiled module compatibility.



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'ext/src/ruby_api/engine.rs', line 211

pub fn precompile_compatibility_key(ruby: &Ruby, rb_self: Obj<Self>) -> Result<RString, Error> {
    static ID: LazyId = LazyId::new("precompile_compatibility_key");
    let ivar_id = LazyId::get_inner_with(&ID, ruby);

    if let Ok(cached) = rb_self.ivar_get::<_, RString>(ivar_id) {
        return Ok(cached);
    }

    let mut hasher = DefaultHasher::new();
    let engine = rb_self.inner.clone();
    engine.precompile_compatibility_hash().hash(&mut hasher);
    let hex_encoded = format!("{:x}", hasher.finish());
    let key = ruby.str_new(&hex_encoded);
    key.freeze();

    rb_self.ivar_set(ivar_id, key)?;

    Ok(key)
}

#precompile_component(wat_or_wasm) ⇒ String

AoT compile a WebAssembly text or WebAssembly binary component for later use.

The compiled component can be instantiated using Component::Component.deserialize.

Parameters:

  • wat_or_wasm (String)

    The String of WAT or Wasm component.

Returns:

  • (String)

    Binary String of the compiled component.

See Also:



194
195
196
197
198
199
200
201
202
203
204
# File 'ext/src/ruby_api/engine.rs', line 194

pub fn precompile_component(
    ruby: &Ruby,
    rb_self: Obj<Self>,
    wat_or_wasm: RString,
) -> Result<RString, Error> {
    let (wat_or_wasm, _guard) = wat_or_wasm.as_locked_slice()?;

    nogvl(|| rb_self.inner.precompile_component(wat_or_wasm))
        .map(|bytes| ruby.str_from_slice(&bytes))
        .map_err(|e| error!("{}", e.to_string()))
}

#precompile_module(wat_or_wasm) ⇒ String

AoT compile a WebAssembly text or WebAssembly binary module for later use.

The compiled module can be instantiated using Module.deserialize.

Parameters:

  • wat_or_wasm (String)

    The String of WAT or Wasm.

Returns:

  • (String)

    Binary String of the compiled module.

See Also:



173
174
175
176
177
178
179
180
181
182
183
# File 'ext/src/ruby_api/engine.rs', line 173

pub fn precompile_module(
    ruby: &Ruby,
    rb_self: Obj<Self>,
    wat_or_wasm: RString,
) -> Result<RString, Error> {
    let (wat_or_wasm, _guard) = wat_or_wasm.as_locked_slice()?;

    nogvl(|| rb_self.inner.precompile_module(wat_or_wasm))
        .map(|bytes| ruby.str_from_slice(&bytes))
        .map_err(|e| error!("{}", e.to_string()))
}

#start_epoch_interval(milliseconds) ⇒ nil

Starts a timer that will increment the engine's epoch every milliseconds. Waits milliseconds before incrementing for the first time.

If a prior timer was started, it will be stopped.

Parameters:

  • milliseconds (Integer)

Returns:

  • (nil)


120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'ext/src/ruby_api/engine.rs', line 120

pub fn start_epoch_interval(&self, milliseconds: u64) {
    self.stop_epoch_interval();
    let engine = self.inner.clone();

    let handle = TOKIO_RT.spawn(async move {
        let tick_every = tokio::time::Duration::from_millis(milliseconds);
        let mut interval = async_timer::Interval::platform_new(tick_every);

        loop {
            interval.wait().await;
            engine.increment_epoch();
        }
    });

    *self.timer_task.lock().unwrap() = Some(handle);
}

#stop_epoch_intervalnil

Stops a previously started timer with #start_epoch_interval. Does nothing if there is no running timer.

Returns:

  • (nil)


142
143
144
145
146
147
148
# File 'ext/src/ruby_api/engine.rs', line 142

pub fn stop_epoch_interval(&self) {
    let maybe_handle = self.timer_task.lock().unwrap().take();

    if let Some(handle) = maybe_handle {
        handle.abort();
    }
}