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
10 changes: 10 additions & 0 deletions crates/perry-codegen/src/expr/instance_misc1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ pub(crate) fn builtin_parent_reserved_class_id(name: &str) -> Option<u32> {
"AggregateError" => 0xFFFF0014,
"EvalError" => 0xFFFF0015,
"URIError" => 0xFFFF0016,
// #6364 — keep in sync with the `lower_instanceof` match above and
// `CLASS_ID_SUPPRESSED_ERROR` so `class X extends SuppressedError {}`
// walks the parent edge and `new X() instanceof SuppressedError` holds.
"SuppressedError" => 0xFFFF003E,
"Date" => 0xFFFF0020,
"RegExp" => 0xFFFF0021,
"Map" => 0xFFFF0022,
Expand Down Expand Up @@ -377,6 +381,12 @@ pub(crate) fn lower(ctx: &mut FnCtx<'_>, expr: &Expr) -> Result<String> {
"AggregateError" => 0xFFFF0014u32,
"EvalError" | "globalThis.EvalError" => 0xFFFF0015u32,
"URIError" | "globalThis.URIError" => 0xFFFF0016u32,
// #6364 — SuppressedError (TC39 explicit-resource-management).
// Must match `CLASS_ID_SUPPRESSED_ERROR` in
// perry-runtime/src/disposable.rs. The instance is a
// GC_TYPE_OBJECT carrying this class id, so the runtime
// class-id chain fast-path matches it (see instanceof.rs).
"SuppressedError" => 0xFFFF003Eu32,
// Uint8Array / Buffer — runtime detects these via a
// thread-local buffer registry (see buffer.rs). The
// TextEncoder path registers its ArrayHeader result
Expand Down
9 changes: 9 additions & 0 deletions crates/perry-hir/src/lower/expr_member/native_dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,15 @@ pub(crate) fn is_native_dispatch_member(module: &str, class: &str, prop: &str) -
// user own-property surface in the bundle walls, so keep dispatching
// for any member to preserve existing behaviour.
"events" | "net" => true,
// #6364 — DisposableStack / AsyncDisposableStack: `disposed` is the
// only native data getter (its value comes from the FFI helper
// `js_disposable_stack_disposed`), so a bare read must dispatch as a
// 0-arg `NativeMethodCall` through the `__disposable__` NativeModSig
// row. Every other member (`use`/`adopt`/`defer`/`dispose`/
// `disposeAsync`/`move`) is a method: a method CALL arrives via the
// call-expression path, and a bare method-VALUE read must stay a plain
// PropertyGet (a bound-method read), never a 0-arg invoking dispatch.
"__disposable__" => prop == "disposed",
// Other native modules historically routed every uncovered member to
// the dispatching fallback. They have no observed user-own-property
// surface, so preserve that: dispatch any member not handled by the
Expand Down
9 changes: 8 additions & 1 deletion crates/perry-runtime/src/disposable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,14 @@ pub const CLASS_ID_DISPOSABLE_STACK: u32 = 0xFFFF_003C;
pub const CLASS_ID_ASYNC_DISPOSABLE_STACK: u32 = 0xFFFF_003D;
/// Reserved class id for a `SuppressedError` instance. Registered as an
/// Error subclass at first construction so `instanceof Error` holds.
pub const CLASS_ID_SUPPRESSED_ERROR: u32 = 0xFFFF_003B;
///
/// #6364 — must stay OUT of the typed-array reserved range
/// (`0xFFFF0030..=0xFFFF003B`, Int8Array..Float16Array). This previously read
/// `0xFFFF_003B`, colliding with `CLASS_ID_FLOAT16_ARRAY`, which made
/// `err instanceof Float16Array` (and the reverse) true once `SuppressedError`
/// was wired into the codegen `instanceof` table. `0xFFFF_003E` is the first
/// free id after the DisposableStack/AsyncDisposableStack block below.
pub const CLASS_ID_SUPPRESSED_ERROR: u32 = 0xFFFF_003E;

const FIELD_DISPOSERS: u32 = 0;
const FIELD_DISPOSED: u32 = 1;
Expand Down
Loading