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 Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions changelog.d/8659-intl402-worklist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Completed the #5896 Test262 Intl402 worklist. Locale canonicalization now applies ICU4X CLDR aliases and likely-subtag data, Intl constructors consistently handle proxy-backed locale and option objects, Collator/PluralRules/RelativeTimeFormat/Segmenter behavior matches the listed ECMA-402 cases, derived Intl classes preserve their native prototypes, and maximum-length arrays stay logically sparse. All 101 pinned worklist tests now pass.
9 changes: 9 additions & 0 deletions changelog.d/8672-method-name-prototype-guards.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
category: Performance
title: Restore method-scoped prototype guards
---

Prototype mutation now invalidates direct-call guards by method-name slot
instead of permanently disabling every method guard in the process. Hash
collisions remain conservative, and dynamic prototype replacement retains a
global fail-closed escape hatch.
1 change: 1 addition & 0 deletions changelog.d/8718-named-pipe-unix-socket-ipc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added local IPC transports to `node:net` (closes #6620). `server.listen(path)`, `net.connect(path)` and the `{ path }` overloads now route through a real Windows named pipe or Unix-domain socket rather than falling back to TCP, reusing the existing socket lifecycle. Connection ordering, connection limits and drop events, close cleanup, `server.address()` and deferred `Socket.connect()` behaviour are preserved, with platform round-trip coverage added.
6 changes: 6 additions & 0 deletions changelog.d/8720-native-value-profile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
### Added

- Stabilized the native value profile with checked exact-width scalars,
source-linked and nested POD layouts, and value-copy semantics across local
assignments and ordinary function boundaries. Invalid or imprecise native
crossings now fail explicitly instead of truncating or losing precision.
56 changes: 54 additions & 2 deletions crates/perry-api-manifest/src/native_abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,20 +226,32 @@ pub enum NativeAbiType {
Json,
/// JavaScript truthiness lowered to a C `i32` boolean slot.
Bool,
/// Signed 8-bit integer slot.
I8,
/// Signed 16-bit integer slot.
I16,
/// Signed 32-bit integer slot.
I32,
/// Signed 64-bit integer slot.
I64,
/// Legacy string return where the native function returns the string
/// pointer as an `i64` instead of a C pointer.
I64String,
/// Unsigned 8-bit integer slot. The manifest spelling `byte` is accepted
/// as an alias and canonicalizes to `u8`.
U8,
/// Unsigned 16-bit integer slot.
U16,
/// Unsigned 32-bit integer slot.
U32,
/// Unsigned 64-bit integer slot.
U64,
/// Pointer-sized unsigned integer slot. Perry's native runtime targets are
/// currently 64-bit, so this lowers as an LLVM `i64`.
USize,
/// Pointer-sized signed integer slot. Perry's native runtime targets are
/// currently 64-bit, so this lowers as an LLVM `i64`.
ISize,
/// 32-bit float slot.
F32,
/// 64-bit float slot. The legacy manifest spelling `"number"` is accepted
Expand Down Expand Up @@ -280,12 +292,17 @@ impl NativeAbiType {
"string" => Ok(Self::String),
"json" => Ok(Self::Json),
"bool" | "boolean" => Ok(Self::Bool),
"i8" => Ok(Self::I8),
"i16" => Ok(Self::I16),
"i32" => Ok(Self::I32),
"i64" => Ok(Self::I64),
"i64_str" => Ok(Self::I64String),
"u8" | "byte" => Ok(Self::U8),
"u16" => Ok(Self::U16),
"u32" => Ok(Self::U32),
"u64" => Ok(Self::U64),
"usize" => Ok(Self::USize),
"isize" => Ok(Self::ISize),
"f32" => Ok(Self::F32),
"f64" | "number" => Ok(Self::F64),
"ptr" => Ok(Self::Ptr),
Expand Down Expand Up @@ -338,12 +355,17 @@ impl NativeAbiType {
Self::String => "string",
Self::Json => "json",
Self::Bool => "bool",
Self::I8 => "i8",
Self::I16 => "i16",
Self::I32 => "i32",
Self::I64 => "i64",
Self::I64String => "i64_str",
Self::U8 => "u8",
Self::U16 => "u16",
Self::U32 => "u32",
Self::U64 => "u64",
Self::USize => "usize",
Self::ISize => "isize",
Self::F32 => "f32",
Self::F64 => "f64",
Self::Ptr => "ptr",
Expand Down Expand Up @@ -419,11 +441,16 @@ impl NativeAbiType {
pub fn is_valid_pod_field(&self) -> bool {
matches!(
self,
Self::I32
Self::I8
| Self::I16
| Self::I32
| Self::I64
| Self::U8
| Self::U16
| Self::U32
| Self::U64
| Self::USize
| Self::ISize
| Self::F32
| Self::F64
| Self::BufferLen
Expand Down Expand Up @@ -464,11 +491,16 @@ impl NativeAbiType {
Self::Pod(_) => "object",
Self::PodAndCount(_) => "PerryPodView<any>",
Self::BufferAndLen => "Buffer",
Self::I32
Self::I8
| Self::I16
| Self::I32
| Self::I64
| Self::U8
| Self::U16
| Self::U32
| Self::U64
| Self::USize
| Self::ISize
| Self::F32
| Self::F64
| Self::BufferLen
Expand Down Expand Up @@ -576,4 +608,24 @@ mod tests {
// Not a scalar POD field.
assert!(!json.is_valid_pod_field());
}

#[test]
fn exact_width_scalar_spellings_are_canonical_and_pod_safe() {
for (spelling, expected, canonical) in [
("i8", NativeAbiType::I8, "i8"),
("i16", NativeAbiType::I16, "i16"),
("u8", NativeAbiType::U8, "u8"),
("byte", NativeAbiType::U8, "u8"),
("u16", NativeAbiType::U16, "u16"),
("isize", NativeAbiType::ISize, "isize"),
] {
let parsed = NativeAbiType::parse_str(spelling).expect("exact-width descriptor");
assert_eq!(parsed, expected);
assert_eq!(parsed.canonical_kind(), canonical);
assert!(parsed.is_valid_param());
assert!(parsed.is_valid_return());
assert!(parsed.is_valid_pod_field());
assert_eq!(parsed.js_type_name(), "number");
}
}
}
16 changes: 11 additions & 5 deletions crates/perry-codegen/src/collectors/proven_this_routing_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -692,11 +692,11 @@ fn guarded_pshape_call_site_is_preceded_by_a_shape_id_guard() {
}

/// The single-pair shape-only arm is small enough to inline at the call site.
/// Pin the complete safety gate: acquire the prototype-mutation latch, accept
/// both the boxed-pointer and internal raw-pointer ABIs, reject addresses
/// outside the target heap range before dereference, reject own descriptors,
/// then compare the exact class/ShapeId pair. The out-of-line guard must be
/// absent from this caller.
/// Pin the complete safety gate: acquire both the all-method escape latch and
/// the FNV-indexed method-name latch, accept both the boxed-pointer and
/// internal raw-pointer ABIs, reject addresses outside the target heap range
/// before dereference, reject own descriptors, then compare the exact
/// class/ShapeId pair. The out-of-line guard must be absent from this caller.
#[test]
fn single_arm_method_shape_guard_is_inlined_with_the_runtime_contract() {
let ir = emit(&guarded_site_module(), false);
Expand All @@ -707,6 +707,12 @@ fn single_arm_method_shape_guard_is_inlined_with_the_runtime_contract() {
),
"the inline guard must acquire the runtime's release-published sticky latch:\n{probe}"
);
assert!(
probe.contains(
"getelementptr i8, ptr @PERRY_CLASS_PROTOTYPE_FAST_GUARDS_INVALIDATED_BY_METHOD",
) && probe.matches("load atomic i8").count() >= 2,
"the inline guard must acquire its method-name invalidation byte:\n{probe}"
);
assert!(
!probe.contains("call i32 @js_method_direct_shape_guard("),
"a monomorphic shape-only site must not retain the out-of-line guard call:\n{probe}"
Expand Down
5 changes: 2 additions & 3 deletions crates/perry-codegen/src/expr/literals_vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@ use crate::lower_string_concat::{
lower_string_self_append_chain,
};
use crate::nanbox::double_literal;
use crate::native_value::MaterializationReason;
use crate::type_analysis::{is_map_expr, is_set_expr, receiver_class_name};
use crate::types::{DOUBLE, I32, I64};

use super::{
can_lower_expr_as_i32_in_current_region, emit_root_nanbox_store_on_block,
emit_shadow_slot_clear, emit_shadow_slot_update_for_expr, emit_write_barrier,
is_global_this_builtin_function_name, lower_expr, lower_expr_as_i32,
lower_pod_local_reassignment, materialize_pod_local, nanbox_string_inline, FnCtx,
lower_pod_local_reassignment, materialize_pod_value_copy, nanbox_string_inline, FnCtx,
TrustedBoxCapturePtr,
};

Expand Down Expand Up @@ -439,7 +438,7 @@ pub(crate) fn lower(ctx: &mut FnCtx<'_>, expr: &Expr) -> Result<String> {
// module-scope `let`s (the ones in `hir.init` at top level).
Expr::LocalGet(id) => {
if ctx.pod_records.contains_key(id) {
return materialize_pod_local(ctx, *id, MaterializationReason::PodMaterialization);
return materialize_pod_value_copy(ctx, *id);
}
// Captured by closure (from outer scope):
if let Some(&capture_idx) = ctx.closure_captures.get(id) {
Expand Down
19 changes: 13 additions & 6 deletions crates/perry-codegen/src/expr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,9 @@ pub(crate) use nanbox_inline::{
pub(crate) use native_record::{array_kind_fact, effect_fact, raw_f64_layout_fact};
pub(crate) use object_literal::lower_object_literal;
pub(crate) use pod_record::{
lower_and_store_initial_pod_field, lower_pod_local_reassignment, materialize_pod_local,
try_lower_pod_field_get, try_lower_pod_field_set,
copy_pod_local, lower_and_store_initial_pod_field, lower_pod_local_reassignment,
materialize_pod_local, materialize_pod_value_copy, try_lower_pod_field_get,
try_lower_pod_field_set,
};
pub(crate) use proven_view_access::{
index_is_exact_i32_shape, local_is_proven_int_store_view,
Expand Down Expand Up @@ -2873,10 +2874,16 @@ fn native_number_to_f64(ctx: &mut FnCtx<'_>, lowered: &LoweredValue) -> Option<S
NativeRep::U32 | NativeRep::BufferLen => {
Some(ctx.block().uitofp(I32, &lowered.value, DOUBLE))
}
NativeRep::I64 | NativeRep::ISize => Some(ctx.block().sitofp(I64, &lowered.value, DOUBLE)),
NativeRep::U64 | NativeRep::USize | NativeRep::HandleId => {
Some(ctx.block().uitofp(I64, &lowered.value, DOUBLE))
}
NativeRep::I64 | NativeRep::ISize => Some(ctx.block().call(
DOUBLE,
"js_native_abi_materialize_i64",
&[(I64, &lowered.value)],
)),
NativeRep::U64 | NativeRep::USize | NativeRep::HandleId => Some(ctx.block().call(
DOUBLE,
"js_native_abi_materialize_u64",
&[(I64, &lowered.value)],
)),
_ => None,
}
}
Expand Down
Loading
Loading