///|
// Engine-private negative symbol IDs are reserved in docs/development.md.
// -101 stores a function object's packed home-realm metadata (ten hot-path
// intrinsic prototypes plus the realm's constructor-prototype registry) and
// optional host-supplied source identity as an 11- or 12-element Array[Value].
// Identity-free functions use 11 elements so the call_value fast path can
// reject identity-bearing metadata with one length check.
// -102..-110 are freed. Keep this comment updated if the range changes.
const FUNCTION_REALM_PROTOS_PACKED_SYMBOL_ID = -101
///|
const FUNCTION_REALM_PROTO_SLOT_COUNT = 11
///|
const FUNCTION_METADATA_SLOT_COUNT = 12
///|
const REALM_PROTO_IDX_FUNCTION = 0
///|
const REALM_PROTO_IDX_OBJECT = 1
///|
const REALM_PROTO_IDX_STRING = 2
///|
const REALM_PROTO_IDX_NUMBER = 3
///|
const REALM_PROTO_IDX_BOOLEAN = 4
///|
const REALM_PROTO_IDX_SYMBOL = 5
///|
const REALM_PROTO_IDX_ARRAY = 6
///|
const REALM_PROTO_IDX_MAP = 7
///|
const REALM_PROTO_IDX_SET = 8
///|
const REALM_PROTO_IDX_PROMISE = 9
///|
const REALM_PROTO_IDX_CONSTRUCTOR_REGISTRY = 10
///|
const FUNCTION_SOURCE_IDENTITY_IDX = 11
///|
pub(all) struct FunctionRealmProtos {
function_proto : Value?
object_proto : Value?
string_proto : Value?
number_proto : Value?
boolean_proto : Value?
symbol_proto : Value?
array_proto : Value?
map_proto : Value?
set_proto : Value?
promise_proto : Value?
constructor_prototype_registry : Value?
}
///|
pub fn FunctionRealmProtos::FunctionRealmProtos(
function_proto? : Value? = None,
object_proto? : Value? = None,
string_proto? : Value? = None,
number_proto? : Value? = None,
boolean_proto? : Value? = None,
symbol_proto? : Value? = None,
array_proto? : Value? = None,
map_proto? : Value? = None,
set_proto? : Value? = None,
promise_proto? : Value? = None,
constructor_prototype_registry? : Value? = None,
) -> FunctionRealmProtos {
{
function_proto,
object_proto,
string_proto,
number_proto,
boolean_proto,
symbol_proto,
array_proto,
map_proto,
set_proto,
promise_proto,
constructor_prototype_registry,
}
}
///|
fn empty_function_realm_protos() -> FunctionRealmProtos {
FunctionRealmProtos()
}
///|
fn active_proto_or_base(
overrides : Ref[FunctionRealmProtos?],
get_proto : (FunctionRealmProtos) -> Value?,
base : Value,
) -> Value {
match overrides.val {
None => base
Some(protos) =>
match get_proto(protos) {
Some(p) => p
None => base
}
}
}
///|
pub fn make_func(data : FuncData) -> Value {
let realm_state = match data.closure.interpreter_context {
Some(interp) => Some(interp.realm_state)
None => data.closure.realm_state
}
let object_proto = get_obj_proto(realm_state~)
let function_proto = get_func_proto(realm_state~)
let realm_protos = function_realm_protos_from_state(realm_state~)
let proto = Object({
bag: PropertyBag(),
prototype: object_proto,
callable: None,
class_name: "Object",
extensible: true,
arraybuffer_state: None,
})
let func_name = match data.name {
Some(n) => n
None => ""
}
let func_length = data.params.length().to_double()
let nf_desc : PropDescriptor = {
writable: false,
enumerable: false,
configurable: true,
getter: None,
setter: None,
is_accessor: false,
}
let func_props : Map[String, Value] = Map([])
let func_descs : Map[String, PropDescriptor] = Map([])
if !data.is_method {
func_props["prototype"] = proto
func_descs["prototype"] = {
writable: true,
enumerable: false,
configurable: false,
getter: None,
setter: None,
is_accessor: false,
}
}
func_props["length"] = Number(func_length)
func_props["name"] = String_(func_name)
func_descs["length"] = nf_desc
func_descs["name"] = nf_desc
let source_identity = source_identity_from_state(realm_state~)
let func_symbol_props = function_realm_symbol_props(
realm_protos, source_identity,
)
let func_obj = Object({
bag: {
properties: func_props,
symbol_properties: func_symbol_props,
descriptors: func_descs,
symbol_descriptors: function_realm_symbol_descs(),
internal_slots: Map([]),
host_slots: Map([]),
},
prototype: function_proto,
callable: Some(UserFunc(data)),
class_name: "Function",
extensible: true,
arraybuffer_state: None,
})
if !data.is_method {
match proto {
Object(proto_data) => {
proto_data.bag.properties["constructor"] = func_obj
proto_data.bag.descriptors["constructor"] = {
writable: true,
enumerable: false,
configurable: true,
getter: None,
setter: None,
is_accessor: false,
}
}
_ => ()
}
}
func_obj
}
///|
/// ES262 §10.2.4 ExpectedArgumentCount for extended parameter lists:
/// count parameters before the first default initializer or rest parameter.
fn expected_argument_count_ext(params : Array[@ast.Param]) -> Int {
for p in params; count = 0 {
if p.default_val is Some(_) || p.is_rest_pattern {
break count
}
continue count + 1
} nobreak {
count
}
}
///|
pub fn make_func_ext(data : FuncDataExt) -> Value {
let realm_state = match data.closure.interpreter_context {
Some(interp) => Some(interp.realm_state)
None => data.closure.realm_state
}
let object_proto = get_obj_proto(realm_state~)
let function_proto = get_func_proto(realm_state~)
let realm_protos = function_realm_protos_from_state(realm_state~)
let proto = Object({
bag: PropertyBag(),
prototype: object_proto,
callable: None,
class_name: "Object",
extensible: true,
arraybuffer_state: None,
})
let func_name = match data.name {
Some(n) => n
None => ""
}
let func_length = expected_argument_count_ext(data.params)
let nf_desc : PropDescriptor = {
writable: false,
enumerable: false,
configurable: true,
getter: None,
setter: None,
is_accessor: false,
}
let func_props : Map[String, Value] = Map([])
let func_descs : Map[String, PropDescriptor] = Map([])
if !data.is_method {
func_props["prototype"] = proto
func_descs["prototype"] = {
writable: true,
enumerable: false,
configurable: false,
getter: None,
setter: None,
is_accessor: false,
}
}
func_props["length"] = Number(func_length.to_double())
func_props["name"] = String_(func_name)
func_descs["length"] = nf_desc
func_descs["name"] = nf_desc
let source_identity = source_identity_from_state(realm_state~)
let func_symbol_props = function_realm_symbol_props(
realm_protos, source_identity,
)
let func_obj = Object({
bag: {
properties: func_props,
symbol_properties: func_symbol_props,
descriptors: func_descs,
symbol_descriptors: function_realm_symbol_descs(),
internal_slots: Map([]),
host_slots: Map([]),
},
prototype: function_proto,
callable: Some(UserFuncExt(data)),
class_name: "Function",
extensible: true,
arraybuffer_state: None,
})
if !data.is_method {
match proto {
Object(proto_data) => {
proto_data.bag.properties["constructor"] = func_obj
proto_data.bag.descriptors["constructor"] = {
writable: true,
enumerable: false,
configurable: true,
getter: None,
setter: None,
is_accessor: false,
}
}
_ => ()
}
}
func_obj
}
///|
/// Rebuild a function value with `has_name_binding: false` on its
/// FuncData/FuncDataExt. Used for method-shorthand definitions (in
/// object literals) where the parser emits FuncExpr/FuncExprExt with
/// `name = Some(key)` for `fn.name` purposes, but §15.2.5's self-name
/// binding does NOT apply. Non-UserFunc/UserFuncExt values pass
/// through unchanged (nothing to strip).
pub fn strip_self_name_binding(v : Value) -> Value {
match v {
Object(data) =>
match data.callable {
Some(UserFunc(fd)) if fd.has_name_binding =>
Object({
..data,
callable: Some(UserFunc({ ..fd, has_name_binding: false })),
})
Some(UserFuncExt(fd)) if fd.has_name_binding =>
Object({
..data,
callable: Some(UserFuncExt({ ..fd, has_name_binding: false })),
})
_ => v
}
_ => v
}
}
///|
/// Mark a function value as a method-shorthand definition (`{ m() {} }`).
/// Per ES §15.4.5 MethodDefinitionEvaluation, such functions have no
/// [[Construct]] internal method and must throw TypeError when called via
/// `new`. Sets `is_method: true` on the FuncData/FuncDataExt.
/// Non-UserFunc/UserFuncExt values (generators, async functions, etc.)
/// pass through unchanged — they have their own non-constructor semantics.
pub fn mark_as_method(v : Value) -> Value {
match v {
Object(data) =>
match data.callable {
Some(UserFunc(fd)) => {
let _ = data.bag.properties.remove("prototype")
let _ = data.bag.descriptors.remove("prototype")
Object({ ..data, callable: Some(UserFunc({ ..fd, is_method: true })) })
}
Some(UserFuncExt(fd)) => {
let _ = data.bag.properties.remove("prototype")
let _ = data.bag.descriptors.remove("prototype")
Object({
..data,
callable: Some(UserFuncExt({ ..fd, is_method: true })),
})
}
_ => v
}
_ => v
}
}
///|
pub fn get_func_proto(realm_state? : RealmState? = None) -> Value {
match realm_state {
Some(realm_state) =>
active_proto_or_base(
realm_state.active_overrides,
p => p.function_proto,
realm_state.get_func_proto(),
)
None => Null
}
}
///|
pub fn get_obj_proto(realm_state? : RealmState? = None) -> Value {
match realm_state {
Some(realm_state) =>
active_proto_or_base(
realm_state.active_overrides,
p => p.object_proto,
realm_state.get_obj_proto(),
)
None => Null
}
}
///|
pub fn get_string_proto(realm_state? : RealmState? = None) -> Value {
match realm_state {
Some(realm_state) =>
active_proto_or_base(
realm_state.active_overrides,
p => p.string_proto,
realm_state.get_string_proto(),
)
None => Null
}
}
///|
pub fn get_number_proto(realm_state? : RealmState? = None) -> Value {
match realm_state {
Some(realm_state) =>
active_proto_or_base(
realm_state.active_overrides,
p => p.number_proto,
realm_state.get_number_proto(),
)
None => Null
}
}
///|
pub fn get_boolean_proto(realm_state? : RealmState? = None) -> Value {
match realm_state {
Some(realm_state) =>
active_proto_or_base(
realm_state.active_overrides,
p => p.boolean_proto,
realm_state.get_boolean_proto(),
)
None => Null
}
}
///|
pub fn get_symbol_proto(realm_state? : RealmState? = None) -> Value {
match realm_state {
Some(realm_state) =>
active_proto_or_base(
realm_state.active_overrides,
p => p.symbol_proto,
realm_state.get_symbol_proto(),
)
None => Null
}
}
///|
pub fn get_array_proto(realm_state? : RealmState? = None) -> Value {
match realm_state {
Some(realm_state) =>
active_proto_or_base(
realm_state.active_overrides,
p => p.array_proto,
realm_state.get_array_proto(),
)
None => Null
}
}
///|
pub fn get_map_proto(realm_state? : RealmState? = None) -> Value {
match realm_state {
Some(realm_state) =>
active_proto_or_base(
realm_state.active_overrides,
p => p.map_proto,
realm_state.get_map_proto(),
)
None => Null
}
}
///|
pub fn get_set_proto(realm_state? : RealmState? = None) -> Value {
match realm_state {
Some(realm_state) =>
active_proto_or_base(
realm_state.active_overrides,
p => p.set_proto,
realm_state.get_set_proto(),
)
None => Null
}
}
///|
pub fn get_promise_proto(realm_state? : RealmState? = None) -> Value {
match realm_state {
Some(realm_state) =>
active_proto_or_base(
realm_state.active_overrides,
p => p.promise_proto,
realm_state.get_promise_proto(),
)
None => Null
}
}
///|
fn get_constructor_prototype_registry(
realm_state? : RealmState? = None,
) -> Value {
match realm_state {
Some(realm_state) =>
active_proto_or_base(
realm_state.active_overrides,
p => p.constructor_prototype_registry,
realm_state.constructor_prototype_registry,
)
None => Null
}
}
///|
/// Build a Function-object shell: `length` and `name` own-data properties with
/// non-enumerable/non-writable/configurable descriptors, `[[Prototype]]` set to
/// `Function.prototype`, `class_name: "Function"`. Shared by all `make_*_func`
/// factories below.
///
/// Insertion order matters: `length` precedes `name` so that `Object.keys` /
/// `Reflect.ownKeys` report `[..., "length", "name"]`, matching the spec order
/// (SetFunctionLength runs before SetFunctionName) and the ordering that the
/// pre-consolidation wrappers produced.
fn build_func_object(
name : String,
length : Int,
callable : Callable,
realm_state? : RealmState? = None,
) -> Value {
let function_proto = get_func_proto(realm_state~)
let realm_protos = function_realm_protos_from_state(realm_state~)
let source_identity = source_identity_from_state(realm_state~)
let nf_desc : PropDescriptor = {
writable: false,
enumerable: false,
configurable: true,
getter: None,
setter: None,
is_accessor: false,
}
Object({
bag: {
properties: {
"length": Number(length.to_double()),
"name": String_(name),
},
symbol_properties: function_realm_symbol_props(
realm_protos, source_identity,
),
descriptors: { "length": nf_desc, "name": nf_desc },
symbol_descriptors: function_realm_symbol_descs(),
internal_slots: Map([]),
host_slots: Map([]),
},
prototype: function_proto,
callable: Some(callable),
class_name: "Function",
extensible: true,
arraybuffer_state: None,
})
}
///|
/// Create the shared object representation for an ECMAScript bound function.
///
/// `prototype` is the exact result of the target's `[[GetPrototypeOf]]`
/// operation (§10.4.1.3 BoundFunctionCreate), so `Null` must not be replaced
/// with the realm's `Function.prototype`.
pub fn make_bound_func(
target : Value,
bound_this : Value,
bound_args : Array[Value],
prototype~ : Value,
name~ : String,
length~ : Double,
realm_state? : RealmState? = None,
) -> Value {
let nf_desc : PropDescriptor = {
writable: false,
enumerable: false,
configurable: true,
getter: None,
setter: None,
is_accessor: false,
}
stamp_function_realm_impl(
Object({
bag: {
properties: { "length": Number(length), "name": String_(name) },
symbol_properties: Map([]),
descriptors: { "length": nf_desc, "name": nf_desc },
symbol_descriptors: Map([]),
internal_slots: Map([]),
host_slots: Map([]),
},
prototype,
callable: Some(BoundFunc(target, bound_this, bound_args.copy())),
class_name: "Function",
extensible: true,
arraybuffer_state: None,
}),
function_realm_protos_from_state(realm_state~),
source_identity_from_state(realm_state~),
false,
)
}
///|
fn function_realm_protos_from_state(
realm_state? : RealmState? = None,
) -> FunctionRealmProtos {
match realm_state {
Some(realm_state) =>
{
function_proto: usable_realm_proto(
get_func_proto(realm_state=Some(realm_state)),
),
object_proto: usable_realm_proto(
get_obj_proto(realm_state=Some(realm_state)),
),
string_proto: usable_realm_proto(
get_string_proto(realm_state=Some(realm_state)),
),
number_proto: usable_realm_proto(
get_number_proto(realm_state=Some(realm_state)),
),
boolean_proto: usable_realm_proto(
get_boolean_proto(realm_state=Some(realm_state)),
),
symbol_proto: usable_realm_proto(
get_symbol_proto(realm_state=Some(realm_state)),
),
array_proto: usable_realm_proto(
get_array_proto(realm_state=Some(realm_state)),
),
map_proto: usable_realm_proto(
get_map_proto(realm_state=Some(realm_state)),
),
set_proto: usable_realm_proto(
get_set_proto(realm_state=Some(realm_state)),
),
promise_proto: usable_realm_proto(
get_promise_proto(realm_state=Some(realm_state)),
),
constructor_prototype_registry: usable_realm_proto(
get_constructor_prototype_registry(realm_state=Some(realm_state)),
),
}
None => empty_function_realm_protos()
}
}
///|
fn function_realm_protos_from_realm_state(
realm_state : RealmState,
) -> FunctionRealmProtos {
{
function_proto: usable_realm_proto(realm_state.get_func_proto()),
object_proto: usable_realm_proto(realm_state.get_obj_proto()),
string_proto: usable_realm_proto(realm_state.get_string_proto()),
number_proto: usable_realm_proto(realm_state.get_number_proto()),
boolean_proto: usable_realm_proto(realm_state.get_boolean_proto()),
symbol_proto: usable_realm_proto(realm_state.get_symbol_proto()),
array_proto: usable_realm_proto(realm_state.get_array_proto()),
map_proto: usable_realm_proto(realm_state.get_map_proto()),
set_proto: usable_realm_proto(realm_state.get_set_proto()),
promise_proto: usable_realm_proto(realm_state.get_promise_proto()),
constructor_prototype_registry: usable_realm_proto(
realm_state.constructor_prototype_registry,
),
}
}
///|
fn make_realm_protos_packed_array(
protos : FunctionRealmProtos,
source_identity? : String? = None,
) -> Value {
let slot_count = match source_identity {
Some(_) => FUNCTION_METADATA_SLOT_COUNT
None => FUNCTION_REALM_PROTO_SLOT_COUNT
}
let e : Array[Value] = Array::make(slot_count, Null)
match protos.function_proto {
Some(v) => e[REALM_PROTO_IDX_FUNCTION] = v
None => ()
}
match protos.object_proto {
Some(v) => e[REALM_PROTO_IDX_OBJECT] = v
None => ()
}
match protos.string_proto {
Some(v) => e[REALM_PROTO_IDX_STRING] = v
None => ()
}
match protos.number_proto {
Some(v) => e[REALM_PROTO_IDX_NUMBER] = v
None => ()
}
match protos.boolean_proto {
Some(v) => e[REALM_PROTO_IDX_BOOLEAN] = v
None => ()
}
match protos.symbol_proto {
Some(v) => e[REALM_PROTO_IDX_SYMBOL] = v
None => ()
}
match protos.array_proto {
Some(v) => e[REALM_PROTO_IDX_ARRAY] = v
None => ()
}
match protos.map_proto {
Some(v) => e[REALM_PROTO_IDX_MAP] = v
None => ()
}
match protos.set_proto {
Some(v) => e[REALM_PROTO_IDX_SET] = v
None => ()
}
match protos.promise_proto {
Some(v) => e[REALM_PROTO_IDX_PROMISE] = v
None => ()
}
match protos.constructor_prototype_registry {
Some(v) => e[REALM_PROTO_IDX_CONSTRUCTOR_REGISTRY] = v
None => ()
}
match source_identity {
Some(identity) => e[FUNCTION_SOURCE_IDENTITY_IDX] = String_(identity)
None => ()
}
Array({
elements: e,
bag: PropertyBag(),
length_writable: false,
holes: Map([]),
extensible: false,
})
}
///|
fn source_identity_from_state(realm_state? : RealmState? = None) -> String? {
match realm_state {
Some(state) => state.active_source_identity.val
None => None
}
}
///|
fn function_realm_symbol_props(
protos : FunctionRealmProtos,
source_identity : String?,
) -> Map[Int, Value] {
let props : Map[Int, Value] = Map([])
props[FUNCTION_REALM_PROTOS_PACKED_SYMBOL_ID] = make_realm_protos_packed_array(
protos,
source_identity~,
)
props
}
///|
fn function_realm_symbol_desc() -> PropDescriptor {
{
writable: false,
enumerable: false,
configurable: false,
getter: None,
setter: None,
is_accessor: false,
}
}
///|
fn function_realm_symbol_descs() -> Map[Int, PropDescriptor] {
let descs : Map[Int, PropDescriptor] = Map([])
descs[FUNCTION_REALM_PROTOS_PACKED_SYMBOL_ID] = function_realm_symbol_desc()
descs
}
///|
fn stamp_function_source_identity(
value : Value,
source_identity : String?,
) -> Unit {
match (value, source_identity) {
(Object(data), Some(identity)) if data.callable is Some(_) =>
match
data.bag.symbol_properties.get(FUNCTION_REALM_PROTOS_PACKED_SYMBOL_ID) {
Some(Array(arr_data)) =>
if arr_data.elements.length() == FUNCTION_SOURCE_IDENTITY_IDX {
arr_data.elements.push(String_(identity))
} else if arr_data.elements.length() > FUNCTION_SOURCE_IDENTITY_IDX {
arr_data.elements[FUNCTION_SOURCE_IDENTITY_IDX] = String_(identity)
}
_ => {
data.bag.symbol_properties[FUNCTION_REALM_PROTOS_PACKED_SYMBOL_ID] = make_realm_protos_packed_array(
empty_function_realm_protos(),
source_identity=Some(identity),
)
data.bag.symbol_descriptors[FUNCTION_REALM_PROTOS_PACKED_SYMBOL_ID] = function_realm_symbol_desc()
}
}
_ => ()
}
}
///|
pub fn function_source_identity(value : Value) -> String? {
match value {
Object(data) =>
match
data.bag.symbol_properties.get(FUNCTION_REALM_PROTOS_PACKED_SYMBOL_ID) {
Some(Array(arr_data)) => {
let own_identity = if arr_data.elements.length() >
FUNCTION_SOURCE_IDENTITY_IDX {
match arr_data.elements[FUNCTION_SOURCE_IDENTITY_IDX] {
String_(identity) => Some(identity)
_ => None
}
} else {
None
}
match own_identity {
Some(_) => own_identity
None =>
match data.callable {
Some(BoundFunc(target, _, _)) =>
function_source_identity(target)
_ => None
}
}
}
_ =>
match data.callable {
Some(BoundFunc(target, _, _)) => function_source_identity(target)
_ => None
}
}
Proxy(proxy_data) =>
match proxy_data.target {
Some(target) => function_source_identity(target)
None => None
}
_ => None
}
}
///|
/// A runtime failure paired with the deepest source identity that propagated
/// unchanged to the observation boundary.
pub struct SourceObservedFailure {
cause_ : Error
source_identity_ : String?
}
///|
fn SourceObservedFailure::SourceObservedFailure(
cause : Error,
source_identity : String?,
) -> SourceObservedFailure {
{ cause_: cause, source_identity_: source_identity }
}
///|
pub fn SourceObservedFailure::cause(self : SourceObservedFailure) -> Error {
self.cause_
}
///|
pub fn SourceObservedFailure::source_identity(
self : SourceObservedFailure,
) -> String? {
self.source_identity_
}
///|
// Preserve the recorded source when a runtime boundary translates an error
// without handling it. This runs only on the failure path.
fn remap_observed_source_failure(
realm_state : RealmState,
previous : Error,
translated : Error,
) -> Unit {
if realm_state.observing_source_failure.val {
match realm_state.observed_source_failure.val {
Some(observed) if physical_equal(observed, previous) =>
realm_state.observed_source_failure.val = Some(translated)
_ => ()
}
}
}
///|
/// Observe source provenance atomically without changing the raised error.
/// Nested call wrappers record an error only while this scope is active.
pub fn[T] observe_source_failure(
realm_state : RealmState,
eval : () -> T raise Error,
) -> Result[T, SourceObservedFailure] {
let previous_observing = realm_state.observing_source_failure.val
let previous_failure = realm_state.observed_source_failure.val
let previous_identity = realm_state.observed_source_identity.val
let previous_overrides = realm_state.active_overrides.val
realm_state.observing_source_failure.val = true
realm_state.observed_source_failure.val = None
realm_state.observed_source_identity.val = None
if previous_overrides is None {
realm_state.active_overrides.val = Some(empty_function_realm_protos())
}
try {
let result = eval()
realm_state.observing_source_failure.val = previous_observing
realm_state.observed_source_failure.val = previous_failure
realm_state.observed_source_identity.val = previous_identity
realm_state.active_overrides.val = previous_overrides
Ok(result)
} catch {
error => {
let source_identity = match realm_state.observed_source_failure.val {
Some(observed) if physical_equal(observed, error) =>
realm_state.observed_source_identity.val
_ => None
}
realm_state.observing_source_failure.val = previous_observing
realm_state.observed_source_failure.val = previous_failure
realm_state.observed_source_identity.val = previous_identity
realm_state.active_overrides.val = previous_overrides
Err(SourceObservedFailure(error, source_identity))
}
}
}
///|
pub fn[T] with_source_identity(
realm_state : RealmState,
source_identity : String?,
eval : () -> T raise Error,
) -> T raise Error {
let previous = realm_state.active_source_identity.val
realm_state.active_source_identity.val = source_identity
try {
let result = eval()
realm_state.active_source_identity.val = previous
result
} catch {
error => {
realm_state.active_source_identity.val = previous
raise error
}
}
}
///|
fn usable_realm_proto(proto : Value) -> Value? {
match proto {
Object(_) => Some(proto)
_ => None
}
}
///|
// Returns the packed function-metadata elements for the callee, following Proxy
// targets. Returns None when no packed entry is present (all slots absent).
fn get_callee_function_metadata(callee : Value) -> Array[Value]? {
match callee {
Object(data) =>
match
data.bag.symbol_properties.get(FUNCTION_REALM_PROTOS_PACKED_SYMBOL_ID) {
Some(Array(arr_data)) => Some(arr_data.elements)
_ => None
}
Proxy(proxy_data) =>
match proxy_data.target {
Some(target) => get_callee_function_metadata(target)
None => None
}
_ => None
}
}
///|
fn stamp_function_realm_impl(
value : Value,
protos : FunctionRealmProtos,
active_source_identity : String?,
set_function_prototype : Bool,
) -> Value {
let stamped = stamp_function_realm_with_protos(
value, protos, set_function_prototype,
)
let source_identity = match active_source_identity {
Some(identity) => Some(identity)
None =>
match stamped {
Object(data) =>
match data.callable {
Some(BoundFunc(target, _, _)) => function_source_identity(target)
_ => None
}
_ => None
}
}
stamp_function_source_identity(stamped, source_identity)
stamped
}
///|
pub fn stamp_function_realm(
value : Value,
realm_state? : RealmState? = None,
) -> Value {
stamp_function_realm_impl(
value,
function_realm_protos_from_state(realm_state~),
source_identity_from_state(realm_state~),
true,
)
}
///|
pub fn stamp_function_realm_with(
value : Value,
function_proto : Value,
object_proto : Value,
string_proto? : Value = Null,
number_proto? : Value = Null,
boolean_proto? : Value = Null,
symbol_proto? : Value = Null,
array_proto? : Value = Null,
map_proto? : Value = Null,
set_proto? : Value = Null,
promise_proto? : Value = Null,
) -> Value {
stamp_function_realm_with_protos(
value,
{
function_proto: usable_realm_proto(function_proto),
object_proto: usable_realm_proto(object_proto),
string_proto: usable_realm_proto(string_proto),
number_proto: usable_realm_proto(number_proto),
boolean_proto: usable_realm_proto(boolean_proto),
symbol_proto: usable_realm_proto(symbol_proto),
array_proto: usable_realm_proto(array_proto),
map_proto: usable_realm_proto(map_proto),
set_proto: usable_realm_proto(set_proto),
promise_proto: usable_realm_proto(promise_proto),
constructor_prototype_registry: None,
},
true,
)
}
///|
fn stamp_realm_proto(
data : ObjectData,
idx : Int,
proto : Value?,
set_function_prototype? : Bool = false,
) -> Unit {
match proto {
Some(proto) => {
if set_function_prototype {
match data.prototype {
Null => data.prototype = proto
_ => ()
}
}
match
data.bag.symbol_properties.get(FUNCTION_REALM_PROTOS_PACKED_SYMBOL_ID) {
Some(Array(arr_data)) => arr_data.elements[idx] = proto
_ => {
let e : Array[Value] = Array::make(
FUNCTION_REALM_PROTO_SLOT_COUNT,
Null,
)
e[idx] = proto
data.bag.symbol_properties[FUNCTION_REALM_PROTOS_PACKED_SYMBOL_ID] = Array({
elements: e,
bag: PropertyBag(),
length_writable: false,
holes: Map([]),
extensible: false,
},
)
data.bag.symbol_descriptors[FUNCTION_REALM_PROTOS_PACKED_SYMBOL_ID] = function_realm_symbol_desc()
}
}
}
None => ()
}
}
///|
fn stamp_realm_proto_if_unstamped(
data : ObjectData,
idx : Int,
proto : Value?,
set_function_prototype? : Bool = false,
) -> Unit {
match proto {
None => ()
Some(proto) => {
let already_set = match
data.bag.symbol_properties.get(FUNCTION_REALM_PROTOS_PACKED_SYMBOL_ID) {
Some(Array(arr_data)) =>
match arr_data.elements[idx] {
Null => false
_ => true
}
_ => false
}
if !already_set {
stamp_realm_proto(data, idx, Some(proto), set_function_prototype~)
}
}
}
}
///|
fn stamp_function_realm_with_protos(
value : Value,
protos : FunctionRealmProtos,
set_function_prototype : Bool,
) -> Value {
match value {
Object(data) =>
match data.callable {
Some(_) => {
stamp_realm_proto(
data,
REALM_PROTO_IDX_FUNCTION,
protos.function_proto,
set_function_prototype~,
)
stamp_realm_proto(data, REALM_PROTO_IDX_OBJECT, protos.object_proto)
stamp_realm_proto(data, REALM_PROTO_IDX_STRING, protos.string_proto)
stamp_realm_proto(data, REALM_PROTO_IDX_NUMBER, protos.number_proto)
stamp_realm_proto(data, REALM_PROTO_IDX_BOOLEAN, protos.boolean_proto)
stamp_realm_proto(data, REALM_PROTO_IDX_SYMBOL, protos.symbol_proto)
stamp_realm_proto(data, REALM_PROTO_IDX_ARRAY, protos.array_proto)
stamp_realm_proto(data, REALM_PROTO_IDX_MAP, protos.map_proto)
stamp_realm_proto(data, REALM_PROTO_IDX_SET, protos.set_proto)
stamp_realm_proto(data, REALM_PROTO_IDX_PROMISE, protos.promise_proto)
stamp_realm_proto(
data,
REALM_PROTO_IDX_CONSTRUCTOR_REGISTRY,
protos.constructor_prototype_registry,
)
}
None => ()
}
_ => ()
}
value
}
///|
fn stamp_function_realm_if_unstamped_with_protos(
value : Value,
protos : FunctionRealmProtos,
) -> Value {
match value {
Object(data) =>
match data.callable {
Some(_) => {
stamp_realm_proto_if_unstamped(
data,
REALM_PROTO_IDX_FUNCTION,
protos.function_proto,
set_function_prototype=true,
)
stamp_realm_proto_if_unstamped(
data,
REALM_PROTO_IDX_OBJECT,
protos.object_proto,
)
stamp_realm_proto_if_unstamped(
data,
REALM_PROTO_IDX_STRING,
protos.string_proto,
)
stamp_realm_proto_if_unstamped(
data,
REALM_PROTO_IDX_NUMBER,
protos.number_proto,
)
stamp_realm_proto_if_unstamped(
data,
REALM_PROTO_IDX_BOOLEAN,
protos.boolean_proto,
)
stamp_realm_proto_if_unstamped(
data,
REALM_PROTO_IDX_SYMBOL,
protos.symbol_proto,
)
stamp_realm_proto_if_unstamped(
data,
REALM_PROTO_IDX_ARRAY,
protos.array_proto,
)
stamp_realm_proto_if_unstamped(
data,
REALM_PROTO_IDX_MAP,
protos.map_proto,
)
stamp_realm_proto_if_unstamped(
data,
REALM_PROTO_IDX_SET,
protos.set_proto,
)
stamp_realm_proto_if_unstamped(
data,
REALM_PROTO_IDX_PROMISE,
protos.promise_proto,
)
stamp_realm_proto_if_unstamped(
data,
REALM_PROTO_IDX_CONSTRUCTOR_REGISTRY,
protos.constructor_prototype_registry,
)
}
None => ()
}
_ => ()
}
value
}
///|
fn stamp_function_realm_from_state_if_unstamped(
value : Value,
realm_state : RealmState,
) -> Value {
stamp_function_realm_if_unstamped_with_protos(
value,
function_realm_protos_from_realm_state(realm_state),
)
}
///|
fn object_data_function_realm_protos(data : ObjectData) -> FunctionRealmProtos {
match data.callable {
None => empty_function_realm_protos()
Some(_) =>
match
data.bag.symbol_properties.get(FUNCTION_REALM_PROTOS_PACKED_SYMBOL_ID) {
Some(Array(arr_data)) => {
let e = arr_data.elements
{
function_proto: usable_realm_proto(e[REALM_PROTO_IDX_FUNCTION]),
object_proto: usable_realm_proto(e[REALM_PROTO_IDX_OBJECT]),
string_proto: usable_realm_proto(e[REALM_PROTO_IDX_STRING]),
number_proto: usable_realm_proto(e[REALM_PROTO_IDX_NUMBER]),
boolean_proto: usable_realm_proto(e[REALM_PROTO_IDX_BOOLEAN]),
symbol_proto: usable_realm_proto(e[REALM_PROTO_IDX_SYMBOL]),
array_proto: usable_realm_proto(e[REALM_PROTO_IDX_ARRAY]),
map_proto: usable_realm_proto(e[REALM_PROTO_IDX_MAP]),
set_proto: usable_realm_proto(e[REALM_PROTO_IDX_SET]),
promise_proto: usable_realm_proto(e[REALM_PROTO_IDX_PROMISE]),
constructor_prototype_registry: usable_realm_proto(
e[REALM_PROTO_IDX_CONSTRUCTOR_REGISTRY],
),
}
}
_ => empty_function_realm_protos()
}
}
}
///|
fn callee_realm_protos(callee : Value) -> FunctionRealmProtos {
match callee {
Object(data) => object_data_function_realm_protos(data)
Proxy(proxy_data) =>
match proxy_data.target {
Some(target) => callee_realm_protos(target)
None => empty_function_realm_protos()
}
_ => empty_function_realm_protos()
}
}
///|
/// Resolve the intrinsic prototype selected by GetPrototypeFromConstructor's
/// primitive-prototype fallback. Proxy and bound-function traversal mirrors
/// GetFunctionRealm; revoked proxies therefore raise before any fallback.
pub fn constructor_realm_intrinsic_prototype(
new_target : Value,
intrinsic_name : String,
default_prototype : Value,
) -> Value raise Error {
fn realm_protos_of(
constructor_value : Value,
) -> FunctionRealmProtos raise Error {
match constructor_value {
Proxy(proxy_data) => realm_protos_of(get_proxy_target(proxy_data))
Object(data) =>
match data.callable {
Some(BoundFunc(target, _, _)) => realm_protos_of(target)
Some(_) => object_data_function_realm_protos(data)
None => empty_function_realm_protos()
}
_ => empty_function_realm_protos()
}
}
let protos = realm_protos_of(new_target)
let registered_prototype = match protos.constructor_prototype_registry {
Some(Object(registry)) => registry.bag.properties.get(intrinsic_name)
_ => None
}
match registered_prototype {
Some(prototype) => prototype
None if intrinsic_name == "Object" =>
protos.object_proto.unwrap_or(default_prototype)
None => default_prototype
}
}
///|
// The packed slot represents a callable's own identity. Bound functions inherit
// their target's identity only when their own slot is absent. Proxy traversal is
// lookup-free here because get_callee_function_metadata already followed it.
fn inherited_function_source_identity(callee : Value) -> String? {
match callee {
Object(data) =>
match data.callable {
Some(BoundFunc(target, _, _)) => function_source_identity(target)
_ => None
}
Proxy(proxy_data) =>
match proxy_data.target {
Some(target) => inherited_function_source_identity(target)
None => None
}
_ => None
}
}
///|
// Returns true when call_value can skip both realm-proto wrapper layers.
// Safe only when every active-override slot is None (no cross-realm context is
// active) AND every callee realm slot is absent or matches the main realm's
// corresponding prototype. All 11 slots are checked in both sets; sampling a
// subset is unsafe because stamp_function_realm_with
// accepts slots independently.
fn realm_fast_path_allowed(callee : Value, realm_state : RealmState) -> Bool {
// Part 1: no active cross-realm override — one Ref read (None = no overrides active)
guard realm_state.active_overrides.val is None else { return false }
// Part 2: source identity and every stamped proto share one packed lookup.
// This avoids both a second HashMap lookup and rebuilding FunctionRealmProtos.
match get_callee_function_metadata(callee) {
None => inherited_function_source_identity(callee) is None
Some(e) => {
guard e.length() == FUNCTION_REALM_PROTO_SLOT_COUNT else { return false }
fn same(idx : Int, main_ref : Ref[Value?]) -> Bool {
match (e[idx], main_ref.val) {
(Null, _) => true // absent slot — inherits same-realm semantics
(Object(c), Some(Object(m))) => physical_equal(c, m)
_ => false // conservative: any mismatch forces slow path
}
}
fn same_value(idx : Int, main : Value) -> Bool {
match (e[idx], main) {
(Null, _) => true
(Object(c), Object(m)) => physical_equal(c, m)
_ => false
}
}
same(REALM_PROTO_IDX_FUNCTION, realm_state.function_prototype) &&
same(REALM_PROTO_IDX_OBJECT, realm_state.object_prototype) &&
same(REALM_PROTO_IDX_STRING, realm_state.string_prototype) &&
same(REALM_PROTO_IDX_NUMBER, realm_state.number_prototype) &&
same(REALM_PROTO_IDX_BOOLEAN, realm_state.boolean_prototype) &&
same(REALM_PROTO_IDX_SYMBOL, realm_state.symbol_prototype) &&
same(REALM_PROTO_IDX_ARRAY, realm_state.array_prototype) &&
same(REALM_PROTO_IDX_MAP, realm_state.map_prototype) &&
same(REALM_PROTO_IDX_SET, realm_state.set_prototype) &&
same(REALM_PROTO_IDX_PROMISE, realm_state.promise_prototype) &&
same_value(
REALM_PROTO_IDX_CONSTRUCTOR_REGISTRY,
realm_state.constructor_prototype_registry,
)
}
}
}
///|
fn active_realm_protos(realm_state : RealmState) -> FunctionRealmProtos {
match realm_state.active_overrides.val {
None => empty_function_realm_protos()
Some(protos) => protos
}
}
///|
// Low-level realm snapshot, not a cleanup capability. Callback adapters and
// the dispatch shell must provide exactly-once, LIFO ownership around it.
priv struct ClearedActiveCalleeRealmScope {
previous_realm_protos : FunctionRealmProtos
}
///|
// Low-level realm/source snapshot, not a cleanup capability. It remains
// copyable semantic data; the dispatch shell owns consumption and ordering.
priv struct ActiveCalleeRealmValueScope {
previous_realm_protos : FunctionRealmProtos
previous_source_identity : String?
callee_source_identity : String?
}
///|
fn begin_cleared_active_callee_realm(
realm_state : RealmState,
) -> ClearedActiveCalleeRealmScope {
let previous_realm_protos = active_realm_protos(realm_state)
apply_active_realm_protos(realm_state, empty_function_realm_protos())
{ previous_realm_protos, }
}
///|
fn finish_cleared_active_callee_realm(
realm_state : RealmState,
scope : ClearedActiveCalleeRealmScope,
) -> Unit {
apply_active_realm_protos(realm_state, scope.previous_realm_protos)
}
///|
fn begin_active_callee_realm_value(
realm_state : RealmState,
callee : Value,
) -> ActiveCalleeRealmValueScope {
let previous_realm_protos = active_realm_protos(realm_state)
let previous_source_identity = realm_state.active_source_identity.val
let callee_source_identity = function_source_identity(callee)
apply_active_realm_protos(realm_state, callee_realm_protos(callee))
realm_state.active_source_identity.val = callee_source_identity
{ previous_realm_protos, previous_source_identity, callee_source_identity }
}
///|
fn record_active_callee_source_failure(
realm_state : RealmState,
scope : ActiveCalleeRealmValueScope,
failure : Error,
) -> Unit {
if realm_state.observing_source_failure.val {
let should_record = match scope.callee_source_identity {
Some(_) =>
match realm_state.observed_source_failure.val {
Some(observed) => !physical_equal(observed, failure)
None => true
}
None => false
}
if should_record {
realm_state.observed_source_failure.val = Some(failure)
realm_state.observed_source_identity.val = scope.callee_source_identity
}
}
}
///|
fn finish_active_callee_realm_value(
realm_state : RealmState,
scope : ActiveCalleeRealmValueScope,
failure~ : Error?,
) -> Unit {
match failure {
Some(error) =>
record_active_callee_source_failure(realm_state, scope, error)
None => ()
}
apply_active_realm_protos(realm_state, scope.previous_realm_protos)
realm_state.active_source_identity.val = scope.previous_source_identity
}
///|
pub fn apply_active_realm_protos(
realm_state : RealmState,
protos : FunctionRealmProtos,
) -> Unit {
let any_set = protos.function_proto is Some(_) ||
protos.object_proto is Some(_) ||
protos.string_proto is Some(_) ||
protos.number_proto is Some(_) ||
protos.boolean_proto is Some(_) ||
protos.symbol_proto is Some(_) ||
protos.array_proto is Some(_) ||
protos.map_proto is Some(_) ||
protos.set_proto is Some(_) ||
protos.promise_proto is Some(_) ||
protos.constructor_prototype_registry is Some(_)
realm_state.active_overrides.val = if any_set ||
realm_state.observing_source_failure.val {
Some(protos)
} else {
None
}
}
///|
fn with_active_callee_realm_value(
realm_state : RealmState,
callee : Value,
eval : () -> Value raise Error,
) -> Value raise Error {
let scope = begin_active_callee_realm_value(realm_state, callee)
try {
let result = eval()
finish_active_callee_realm_value(realm_state, scope, failure=None)
result
} catch {
e => {
finish_active_callee_realm_value(realm_state, scope, failure=Some(e))
raise e
}
}
}
///|
fn[T] with_cleared_active_callee_realm(
realm_state : RealmState,
eval : () -> T raise Error,
) -> T raise Error {
let scope = begin_cleared_active_callee_realm(realm_state)
try {
let result = eval()
finish_cleared_active_callee_realm(realm_state, scope)
result
} catch {
e => {
finish_cleared_active_callee_realm(realm_state, scope)
raise e
}
}
}
///|
fn with_cleared_active_callee_realm_unit(
realm_state : RealmState,
eval : () -> Unit,
) -> Unit {
let scope = begin_cleared_active_callee_realm(realm_state)
eval()
finish_cleared_active_callee_realm(realm_state, scope)
}
///|
pub fn with_active_realm_state_unit(
realm_state : RealmState,
eval : () -> Unit,
) -> Unit {
with_cleared_active_callee_realm_unit(realm_state, fn() { eval() })
}
///|
/// Non-constructable native function: callback is `(Array[Value]) -> Value raise Error`.
/// Use for built-in free functions and static methods.
pub fn make_native_func(
name~ : String,
length? : Int = 0,
realm_state? : RealmState? = None,
func : (Array[Value]) -> Value raise Error,
) -> Value {
build_func_object(
name,
length,
NonConstructableCallable(name, func),
realm_state~,
)
}
///|
/// Method function: callback receives `this`. Signature
/// `(Value, Array[Value]) -> Value raise Error`.
pub fn make_method_func(
name~ : String,
length? : Int = 0,
realm_state? : RealmState? = None,
func : (Value, Array[Value]) -> Value raise Error,
) -> Value {
build_func_object(name, length, MethodCallable(name, func), realm_state~)
}
///|
/// Interpreter-aware method function: callback receives interpreter and `this`.
/// Signature `(Interpreter, Value, Array[Value]) -> Value raise Error`.
pub fn make_interp_method_func(
name~ : String,
length? : Int = 0,
realm_state? : RealmState? = None,
func : (Interpreter, Value, Array[Value]) -> Value raise Error,
) -> Value {
build_func_object(name, length, InterpreterCallable(name, func), realm_state~)
}
///|
/// Interpreter-aware method function with explicit call/construct context.
pub fn make_interp_method_func_with_context(
name~ : String,
length? : Int = 0,
func : (Interpreter, CallContext, Value, Array[Value]) -> Value raise Error,
) -> Value {
build_func_object(name, length, InterpreterCallableWithContext(name, func))
}
///|
/// Interpreter-aware static function: callback receives interpreter but not `this`.
/// Signature `(Interpreter, Array[Value]) -> Value raise Error`.
pub fn make_interp_static_func(
name~ : String,
length? : Int = 0,
func : (Interpreter, Array[Value]) -> Value raise Error,
) -> Value {
build_func_object(
name,
length,
NonConstructableInterpreterCallable(name, func),
)
}
///|
/// Helper to create a basic object with default empty symbol maps
pub fn make_object(
properties : Map[String, Value],
prototype : Value,
callable : Callable?,
class_name : String,
descriptors : Map[String, PropDescriptor],
extensible : Bool,
) -> Value {
Object({
bag: {
properties,
symbol_properties: Map([]),
descriptors,
symbol_descriptors: Map([]),
internal_slots: Map([]),
host_slots: Map([]),
},
prototype,
callable,
class_name,
extensible,
arraybuffer_state: None,
})
}
///|
/// Create a host object with methods, accessors, intent-shaped data properties,
/// and embedder host slots (#517). Returns `Value` so callers need not match
/// on `ObjectData`. Composes `install_builtin_*` and `set_host_slot`.
///
/// **Parameters**
/// - `name` — `[[Class]]` / `class_name` string (e.g. `"Element"`).
/// - `proto` — `[[Prototype]]`. Defaults to `Null` (not `%Object.prototype%`);
/// pass a realm object prototype when the host object should inherit from it.
/// - `methods` — string-keyed callables with builtin method descriptors.
/// - `accessors` — map of name → `(getter?, setter?)`. At least one side must
/// be `Some`; use `None` for an absent side.
/// - `non_writable` / `frozen` — rare constant data props (builtin descriptors).
/// - `host_slots` — embedder-private state keyed by pre-reserved `HostSlotKey`
/// values (`HostSlotKey::reserve()` once per slot kind, then build the map).
/// - `extensible` — `[[Extensible]]` (default `true`).
///
/// **Install order:** `non_writable` → `frozen` → `methods` → `accessors` →
/// `host_slots`. Same string key across the JS maps: later step wins (factory
/// stomping, not `[[DefineOwnProperty]]` — avoid dual-defining the same name,
/// including overwriting a `frozen` key).
pub fn make_host_object(
name~ : String,
proto? : Value = Null,
methods? : Map[String, Value] = Map([]),
accessors? : Map[String, (Value?, Value?)] = Map([]),
non_writable? : Map[String, Value] = Map([]),
frozen? : Map[String, Value] = Map([]),
host_slots? : Map[HostSlotKey, Value] = Map([]),
extensible? : Bool = true,
) -> Value {
let obj = make_object(Map([]), proto, None, name, Map([]), extensible)
guard obj is Object(data) else {
abort("make_host_object: make_object must return Object")
}
non_writable.each(fn(k, v) { install_builtin_non_writable(data, k, v) })
frozen.each(fn(k, v) { install_builtin_frozen_data(data, k, v) })
methods.each(fn(k, v) { install_builtin_method(data, k, v) })
accessors.each(fn(k, pair) {
let (getter, setter) = pair
install_builtin_accessor(data, k, getter, setter)
})
host_slots.each(fn(k, v) { set_host_slot(data, k, v) })
obj
}
///|
/// Create an iterator result object { value, done }
pub fn create_iter_result(value : Value, done : Bool) -> Value {
let props : Map[String, Value] = Map([])
props["value"] = value
props["done"] = Bool(done)
Object({
bag: {
properties: props,
symbol_properties: Map([]),
descriptors: Map([]),
symbol_descriptors: Map([]),
internal_slots: Map([]),
host_slots: Map([]),
},
prototype: Null,
callable: None,
class_name: "Object",
extensible: true,
arraybuffer_state: None,
})
}
///|
/// Helper to create a plain object
pub fn make_plain_object() -> Value {
Object({
bag: PropertyBag(),
prototype: Null,
callable: None,
class_name: "Object",
extensible: true,
arraybuffer_state: None,
})
}
///|
/// Wrap an Array[Value] in an Array Value with an empty property bag.
/// Dense-only arrays (no named props, no sparse length overrides) build via this.
pub fn make_array(elements : Array[Value]) -> Value {
Array({
elements,
bag: PropertyBag(),
length_writable: true,
holes: Map([]),
extensible: true,
})
}
///|
/// Wrap an Array[Value] with an explicit instance prototype.
/// Constructor adapters use this after resolving newTarget.prototype and
/// before exposing the newly allocated Array value.
pub fn make_array_with_prototype(
elements : Array[Value],
prototype : Value,
) -> Value {
let data : ArrayData = {
elements,
bag: PropertyBag(),
length_writable: true,
holes: Map([]),
extensible: true,
}
set_array_prototype_override(data, prototype)
Array(data)
}
///|
/// Wrap an Array[Value] and mark selected indices as array holes.
pub fn make_array_with_holes(
elements : Array[Value],
hole_indices : Array[Int],
) -> Value {
let arr = make_array(elements)
match arr {
Array(data) =>
for i in hole_indices {
data.holes[i] = ()
}
_ => ()
}
arr
}