Skip to content

Commit df9ab18

Browse files
committed
Re-internalize ResourceKind to mod handle_table
1 parent 78a089b commit df9ab18

3 files changed

Lines changed: 150 additions & 106 deletions

File tree

crates/wasmtime/src/runtime/vm/component.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ mod resources;
3737

3838
#[cfg(feature = "component-model-async")]
3939
pub use self::handle_table::{HandleKind, TransmitLocalState};
40-
pub use self::handle_table::{HandleTable, ResourceKind};
40+
pub use self::handle_table::{HandleTable, RemovedResource};
4141
#[cfg(feature = "component-model-async")]
4242
pub use self::resources::CallContext;
4343
pub use self::resources::{CallContexts, ResourceTables, TypedResource, TypedResourceIndex};

crates/wasmtime/src/runtime/vm/component/handle_table.rs

Lines changed: 133 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ pub enum HandleKind {
5454
},
5555
}
5656

57-
pub enum ResourceKind {
57+
enum ResourceKind {
5858
/// Represents an owned resource handle with the listed representation.
5959
///
6060
/// The `lend_count` tracks how many times this has been lent out as a
@@ -74,6 +74,14 @@ pub enum ResourceKind {
7474
},
7575
}
7676

77+
/// Return value from [`HandleTable::remove_resource`].
78+
pub enum RemovedResource {
79+
/// An `own` resource was removed with the specified `rep`
80+
Own { rep: u32 },
81+
/// A `borrow` resource was removed originally created within `scope`.
82+
Borrow { scope: usize },
83+
}
84+
7785
enum Slot {
7886
Free { next: u32 },
7987
Handle { rep: u32, kind: HandleKind },
@@ -132,38 +140,48 @@ impl HandleTable {
132140
Ok(ret)
133141
}
134142

135-
pub fn insert_resource(&mut self, kind: ResourceKind) -> Result<u32> {
136-
self.insert(Slot::Resource { kind })
143+
fn handle_index_to_table_index(&self, idx: u32) -> Option<usize> {
144+
// NB: `idx` is decremented by one to account for the `+1` above during
145+
// allocation.
146+
let idx = idx.checked_sub(1)?;
147+
usize::try_from(idx).ok()
137148
}
138149

139-
pub fn insert_handle(&mut self, rep: u32, kind: HandleKind) -> Result<u32> {
140-
if matches!(self
141-
.reps_to_indexes
142-
.get(usize::try_from(rep).unwrap()), Some(idx) if *idx != 0)
143-
{
144-
bail!("rep {rep} already exists in this table");
145-
}
146-
147-
let ret = self.insert(Slot::Handle { rep, kind })?;
148-
149-
let rep = usize::try_from(rep).unwrap();
150-
if self.reps_to_indexes.len() <= rep {
151-
self.reps_to_indexes.resize(rep.checked_add(1).unwrap(), 0);
150+
fn get_mut(&mut self, idx: u32) -> Result<&mut Slot> {
151+
let slot = self
152+
.handle_index_to_table_index(idx)
153+
.and_then(|i| self.slots.get_mut(i));
154+
match slot {
155+
None | Some(Slot::Free { .. }) => bail!("unknown handle index {idx}"),
156+
Some(slot) => Ok(slot),
152157
}
158+
}
153159

154-
self.reps_to_indexes[rep] = ret;
155-
156-
Ok(ret)
160+
/// Inserts a new `own` resource into this table whose type/rep are
161+
/// specified by `resource`.
162+
pub fn insert_own_resource(&mut self, resource: TypedResource) -> Result<u32> {
163+
self.insert(Slot::Resource {
164+
kind: ResourceKind::Own {
165+
resource,
166+
lend_count: 0,
167+
},
168+
})
157169
}
158170

159-
fn handle_index_to_table_index(&self, idx: u32) -> Option<usize> {
160-
// NB: `idx` is decremented by one to account for the `+1` above during
161-
// allocation.
162-
let idx = idx.checked_sub(1)?;
163-
usize::try_from(idx).ok()
171+
/// Inserts a new `borrow` resource into this table whose type/rep are
172+
/// specified by `resource`. The `scope` specified is used by
173+
/// `CallContexts` to manage lending information.
174+
pub fn insert_borrow_resource(&mut self, resource: TypedResource, scope: usize) -> Result<u32> {
175+
self.insert(Slot::Resource {
176+
kind: ResourceKind::Borrow { resource, scope },
177+
})
164178
}
165179

166-
pub(super) fn resource_rep(&self, idx: TypedResourceIndex) -> Result<u32> {
180+
/// Returns the internal "rep" of the resource specified by `idx`.
181+
///
182+
/// Returns an error if `idx` is out-of-bounds or doesn't point to a
183+
/// resource of the appropriate type.
184+
pub fn resource_rep(&self, idx: TypedResourceIndex) -> Result<u32> {
167185
let slot = self
168186
.handle_index_to_table_index(idx.raw_index())
169187
.and_then(|i| self.slots.get(i));
@@ -178,30 +196,101 @@ impl HandleTable {
178196
}
179197
}
180198

181-
fn get_mut(&mut self, idx: u32) -> Result<&mut Slot> {
182-
let slot = self
183-
.handle_index_to_table_index(idx)
184-
.and_then(|i| self.slots.get_mut(i));
185-
match slot {
186-
None | Some(Slot::Free { .. }) => bail!("unknown handle index {idx}"),
187-
Some(slot) => Ok(slot),
199+
/// Accesses the "rep" of the resource pointed to by `idx` as part of a
200+
/// lending operation.
201+
///
202+
/// This will increase `lend_count` for owned resources and must be paired
203+
/// with a `resource_undo_lend` below later on (managed by `CallContexts`).
204+
///
205+
/// Upon success returns the "rep" plus whether the borrow came from an
206+
/// `own` handle.
207+
pub fn resource_lend(&mut self, idx: TypedResourceIndex) -> Result<(u32, bool)> {
208+
match self.get_mut(idx.raw_index())? {
209+
Slot::Resource {
210+
kind:
211+
ResourceKind::Own {
212+
resource,
213+
lend_count,
214+
},
215+
} => {
216+
let rep = resource.rep(&idx)?;
217+
*lend_count = lend_count.checked_add(1).unwrap();
218+
Ok((rep, true))
219+
}
220+
Slot::Resource {
221+
kind: ResourceKind::Borrow { resource, .. },
222+
} => Ok((resource.rep(&idx)?, false)),
223+
_ => bail!("index {} is not a resource", idx.raw_index()),
188224
}
189225
}
190226

191-
pub(super) fn get_mut_resource(
192-
&mut self,
193-
idx: TypedResourceIndex,
194-
) -> Result<&mut ResourceKind> {
195-
let slot = self
196-
.handle_index_to_table_index(idx.raw_index())
197-
.and_then(|i| self.slots.get_mut(i));
198-
match slot {
199-
None | Some(Slot::Free { .. }) => bail!("unknown handle index {}", idx.raw_index()),
200-
Some(Slot::Handle { .. }) => {
201-
bail!("index {} is a handle, not a resource", idx.raw_index())
227+
/// For `own` resources that were borrowed in `resource_lend`, undoes the
228+
/// lending operation.
229+
pub fn resource_undo_lend(&mut self, idx: TypedResourceIndex) -> Result<()> {
230+
match self.get_mut(idx.raw_index())? {
231+
Slot::Resource {
232+
kind: ResourceKind::Own { lend_count, .. },
233+
} => {
234+
*lend_count -= 1;
235+
Ok(())
236+
}
237+
_ => bail!("index {} is not an own resource", idx.raw_index()),
238+
}
239+
}
240+
241+
/// Removes the resource specified by `idx` from the table.
242+
///
243+
/// This can fail if `idx` doesn't point to a resource, points to a
244+
/// borrowed resource, or points to a resource of the wrong type.
245+
pub fn remove_resource(&mut self, idx: TypedResourceIndex) -> Result<RemovedResource> {
246+
let to_fill = Slot::Free { next: self.next };
247+
let slot = self.get_mut(idx.raw_index())?;
248+
let ret = match slot {
249+
Slot::Resource {
250+
kind:
251+
ResourceKind::Own {
252+
resource,
253+
lend_count,
254+
},
255+
} => {
256+
if *lend_count != 0 {
257+
bail!("cannot remove owned resource while borrowed")
258+
}
259+
RemovedResource::Own {
260+
rep: resource.rep(&idx)?,
261+
}
262+
}
263+
Slot::Resource {
264+
kind: ResourceKind::Borrow { resource, scope },
265+
} => {
266+
// Ensure the drop is done with the right type
267+
resource.rep(&idx)?;
268+
RemovedResource::Borrow { scope: *scope }
202269
}
203-
Some(Slot::Resource { kind }) => Ok(kind),
270+
_ => bail!("index {} is not a resource", idx.raw_index()),
271+
};
272+
*slot = to_fill;
273+
Ok(ret)
274+
}
275+
276+
pub fn insert_handle(&mut self, rep: u32, kind: HandleKind) -> Result<u32> {
277+
if matches!(self
278+
.reps_to_indexes
279+
.get(usize::try_from(rep).unwrap()), Some(idx) if *idx != 0)
280+
{
281+
bail!("rep {rep} already exists in this table");
282+
}
283+
284+
let ret = self.insert(Slot::Handle { rep, kind })?;
285+
286+
let rep = usize::try_from(rep).unwrap();
287+
if self.reps_to_indexes.len() <= rep {
288+
self.reps_to_indexes.resize(rep.checked_add(1).unwrap(), 0);
204289
}
290+
291+
self.reps_to_indexes[rep] = ret;
292+
293+
Ok(ret)
205294
}
206295

207296
pub fn get_mut_handle_by_index(&mut self, idx: u32) -> Result<(u32, &mut HandleKind)> {
@@ -225,17 +314,6 @@ impl HandleTable {
225314
}
226315
}
227316

228-
pub(super) fn remove_resource(&mut self, idx: TypedResourceIndex) -> Result<ResourceKind> {
229-
_ = self.resource_rep(idx)?;
230-
231-
let to_fill = Slot::Free { next: self.next };
232-
let Slot::Resource { kind } = mem::replace(self.get_mut(idx.raw_index())?, to_fill) else {
233-
unreachable!()
234-
};
235-
self.next = idx.raw_index() - 1;
236-
Ok(kind)
237-
}
238-
239317
pub fn remove_handle_by_index(&mut self, idx: u32) -> Result<(u32, HandleKind)> {
240318
_ = self.get_mut_handle_by_index(idx)?;
241319

crates/wasmtime/src/runtime/vm/component/resources.rs

Lines changed: 16 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
//! about ABI details can be found in lifting/lowering throughout Wasmtime,
2121
//! namely in the `Resource<T>` and `ResourceAny` types.
2222
23-
use super::{HandleTable, ResourceKind};
23+
use super::{HandleTable, RemovedResource};
2424
use crate::prelude::*;
2525
use core::error::Error;
2626
use core::fmt;
@@ -217,10 +217,7 @@ impl ResourceTables<'_> {
217217
/// Note that this is the same as `resource_lower_own`.
218218
pub fn resource_new(&mut self, resource: TypedResource) -> Result<u32> {
219219
self.table_for_resource(&resource)
220-
.insert_resource(ResourceKind::Own {
221-
resource,
222-
lend_count: 0,
223-
})
220+
.insert_own_resource(resource)
224221
}
225222

226223
/// Implementation of the `resource.rep` canonical intrinsic.
@@ -245,17 +242,8 @@ impl ResourceTables<'_> {
245242
/// removed and no destructor is necessary.
246243
pub fn resource_drop(&mut self, index: TypedResourceIndex) -> Result<Option<u32>> {
247244
match self.table_for_index(&index).remove_resource(index)? {
248-
ResourceKind::Own {
249-
resource,
250-
lend_count: 0,
251-
} => resource.rep(&index).map(Some),
252-
ResourceKind::Own { .. } => bail!("cannot remove owned resource while borrowed"),
253-
ResourceKind::Borrow {
254-
scope, resource, ..
255-
} => {
256-
// Validate that this borrow has the correct type to ensure a
257-
// trap is returned if this is a mis-typed `resource.drop`.
258-
resource.rep(&index)?;
245+
RemovedResource::Own { rep } => Ok(Some(rep)),
246+
RemovedResource::Borrow { scope } => {
259247
self.calls.scopes[scope].borrow_count -= 1;
260248
Ok(None)
261249
}
@@ -273,10 +261,7 @@ impl ResourceTables<'_> {
273261
/// This is an implementation of the canonical ABI `lower_own` function.
274262
pub fn resource_lower_own(&mut self, resource: TypedResource) -> Result<u32> {
275263
self.table_for_resource(&resource)
276-
.insert_resource(ResourceKind::Own {
277-
resource,
278-
lend_count: 0,
279-
})
264+
.insert_own_resource(resource)
280265
}
281266

282267
/// Attempts to remove an "own" handle from the specified table and its
@@ -289,12 +274,8 @@ impl ResourceTables<'_> {
289274
/// This is an implementation of the canonical ABI `lift_own` function.
290275
pub fn resource_lift_own(&mut self, index: TypedResourceIndex) -> Result<u32> {
291276
match self.table_for_index(&index).remove_resource(index)? {
292-
ResourceKind::Own {
293-
resource,
294-
lend_count: 0,
295-
} => resource.rep(&index),
296-
ResourceKind::Own { .. } => bail!("cannot remove owned resource while borrowed"),
297-
ResourceKind::Borrow { .. } => bail!("cannot lift own resource from a borrow"),
277+
RemovedResource::Own { rep } => Ok(rep),
278+
RemovedResource::Borrow { .. } => bail!("cannot lift own resource from a borrow"),
298279
}
299280
}
300281

@@ -308,20 +289,12 @@ impl ResourceTables<'_> {
308289
///
309290
/// This is an implementation of the canonical ABI `lift_borrow` function.
310291
pub fn resource_lift_borrow(&mut self, index: TypedResourceIndex) -> Result<u32> {
311-
match self.table_for_index(&index).get_mut_resource(index)? {
312-
ResourceKind::Own {
313-
resource,
314-
lend_count,
315-
} => {
316-
let rep = resource.rep(&index)?;
317-
// The decrement to this count happens in `exit_call`.
318-
*lend_count = lend_count.checked_add(1).unwrap();
319-
let scope = self.calls.scopes.last_mut().unwrap();
320-
scope.lenders.push(index);
321-
Ok(rep)
322-
}
323-
ResourceKind::Borrow { resource, .. } => resource.rep(&index),
292+
let (rep, is_own) = self.table_for_index(&index).resource_lend(index)?;
293+
if is_own {
294+
let scope = self.calls.scopes.last_mut().unwrap();
295+
scope.lenders.push(index);
324296
}
297+
Ok(rep)
325298
}
326299

327300
/// Records a new `borrow` resource with the given representation within the
@@ -341,7 +314,7 @@ impl ResourceTables<'_> {
341314
let borrow_count = &mut self.calls.scopes.last_mut().unwrap().borrow_count;
342315
*borrow_count = borrow_count.checked_add(1).unwrap();
343316
self.table_for_resource(&resource)
344-
.insert_resource(ResourceKind::Borrow { resource, scope })
317+
.insert_borrow_resource(resource, scope)
345318
}
346319

347320
/// Enters a new calling context, starting a fresh count of borrows and
@@ -366,16 +339,9 @@ impl ResourceTables<'_> {
366339
// Note the panics here which should never get triggered in theory
367340
// due to the dynamic tracking of borrows and such employed for
368341
// resources.
369-
match self
370-
.table_for_index(lender)
371-
.get_mut_resource(*lender)
372-
.unwrap()
373-
{
374-
ResourceKind::Own { lend_count, .. } => {
375-
*lend_count -= 1;
376-
}
377-
_ => unreachable!(),
378-
}
342+
self.table_for_index(lender)
343+
.resource_undo_lend(*lender)
344+
.unwrap();
379345
}
380346
Ok(())
381347
}

0 commit comments

Comments
 (0)