Skip to content

Commit b080170

Browse files
committed
refactor(vm): move typed array shared-atomics helpers into typedarray module
1 parent 117cec4 commit b080170

3 files changed

Lines changed: 184 additions & 184 deletions

File tree

src/core/function_id.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -339,15 +339,15 @@ pub(crate) const BUILTIN_ATOMICS_LOAD: FunctionID = 491;
339339
pub(crate) const BUILTIN_ATOMICS_STORE: FunctionID = 492;
340340
pub(crate) const BUILTIN_ATOMICS_COMPAREEXCHANGE: FunctionID = 493;
341341
pub(crate) const BUILTIN_ATOMICS_ADD: FunctionID = 494;
342-
pub(crate) const BUILTIN_ATOMICS_SUB: FunctionID = 500;
343-
pub(crate) const BUILTIN_ATOMICS_AND: FunctionID = 501;
344-
pub(crate) const BUILTIN_ATOMICS_OR: FunctionID = 502;
345-
pub(crate) const BUILTIN_ATOMICS_XOR: FunctionID = 503;
346-
pub(crate) const BUILTIN_ATOMICS_EXCHANGE: FunctionID = 495;
347-
pub(crate) const BUILTIN_ATOMICS_WAIT: FunctionID = 496;
348-
pub(crate) const BUILTIN_ATOMICS_NOTIFY: FunctionID = 497;
349-
pub(crate) const BUILTIN_ATOMICS_WAITASYNC: FunctionID = 498;
350-
pub(crate) const BUILTIN_ATOMICS_PAUSE: FunctionID = 499;
342+
pub(crate) const BUILTIN_ATOMICS_SUB: FunctionID = 495;
343+
pub(crate) const BUILTIN_ATOMICS_AND: FunctionID = 496;
344+
pub(crate) const BUILTIN_ATOMICS_OR: FunctionID = 497;
345+
pub(crate) const BUILTIN_ATOMICS_XOR: FunctionID = 498;
346+
pub(crate) const BUILTIN_ATOMICS_EXCHANGE: FunctionID = 499;
347+
pub(crate) const BUILTIN_ATOMICS_WAIT: FunctionID = 500;
348+
pub(crate) const BUILTIN_ATOMICS_NOTIFY: FunctionID = 501;
349+
pub(crate) const BUILTIN_ATOMICS_WAITASYNC: FunctionID = 502;
350+
pub(crate) const BUILTIN_ATOMICS_PAUSE: FunctionID = 503;
351351
// ── AbstractModuleSource (510–514) ──────────────────────────────────
352352
pub(crate) const BUILTIN_CTOR_ABSTRACT_MODULE_SOURCE: FunctionID = 510;
353353
pub(crate) const BUILTIN_ABSTRACT_MODULE_SOURCE_TOSTRINGTAG_GET: FunctionID = 511;

src/core/vm.rs

Lines changed: 0 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -968,181 +968,6 @@ impl<'gc> VM<'gc> {
968968
Some(id)
969969
}
970970

971-
fn shared_ta_info(&self, arr: &ArrayHandle<'gc>) -> Option<(u64, usize, usize, String)> {
972-
let borrow = arr.borrow();
973-
let Value::Object(buf_obj) = borrow.props.get("__typedarray_buffer__")?.clone() else {
974-
return None;
975-
};
976-
let shared_id = self.shared_buffer_id_from_obj(&buf_obj)?;
977-
let byte_offset = borrow
978-
.props
979-
.get("__byte_offset__")
980-
.and_then(|v| if let Value::Number(n) = v { Some(*n as usize) } else { None })
981-
.unwrap_or(0);
982-
let bpe = borrow
983-
.props
984-
.get("__bytes_per_element__")
985-
.and_then(|v| {
986-
if let Value::Number(n) = v {
987-
Some((*n as usize).max(1))
988-
} else {
989-
None
990-
}
991-
})
992-
.unwrap_or(1);
993-
let ta_name = borrow.props.get("__typedarray_name__").map(value_to_string).unwrap_or_default();
994-
Some((shared_id, byte_offset, bpe, ta_name))
995-
}
996-
997-
fn ensure_shared_ta_info(&mut self, ctx: &GcContext<'gc>, arr: &ArrayHandle<'gc>) -> Option<(u64, usize, usize, String)> {
998-
let buf_obj = {
999-
let borrow = arr.borrow();
1000-
let Value::Object(buf_obj) = borrow.props.get("__typedarray_buffer__")?.clone() else {
1001-
return None;
1002-
};
1003-
buf_obj
1004-
};
1005-
self.ensure_shared_buffer_id(ctx, &buf_obj)?;
1006-
self.shared_ta_info(arr)
1007-
}
1008-
1009-
fn shared_ta_read_element(&self, arr: &ArrayHandle<'gc>, idx: usize) -> Option<Value<'gc>> {
1010-
let (shared_id, byte_offset, bpe, ta_name) = self.shared_ta_info(arr)?;
1011-
let base = byte_offset.checked_add(idx.checked_mul(bpe)?)?;
1012-
let raw = crate::js_agent::shared_buffer_read(shared_id, base, bpe)?;
1013-
let bytes: Vec<Value<'gc>> = raw.into_iter().map(|b| Value::Number(b as f64)).collect();
1014-
Some(Self::decode_typed_element(&bytes, 0, bpe, &ta_name))
1015-
}
1016-
1017-
fn local_ta_read_element(&self, arr: &ArrayHandle<'gc>, idx: usize) -> Option<Value<'gc>> {
1018-
let (buf_obj, byte_offset, bpe, ta_name) = {
1019-
let borrow = arr.borrow();
1020-
let Value::Object(buf_obj) = borrow.props.get("__typedarray_buffer__")?.clone() else {
1021-
return None;
1022-
};
1023-
let byte_offset = borrow
1024-
.props
1025-
.get("__byte_offset__")
1026-
.and_then(|v| if let Value::Number(n) = v { Some(*n as usize) } else { None })
1027-
.unwrap_or(0);
1028-
let bpe = borrow
1029-
.props
1030-
.get("__bytes_per_element__")
1031-
.and_then(|v| {
1032-
if let Value::Number(n) = v {
1033-
Some((*n as usize).max(1))
1034-
} else {
1035-
None
1036-
}
1037-
})
1038-
.unwrap_or(1);
1039-
let ta_name = borrow.props.get("__typedarray_name__").map(value_to_string).unwrap_or_default();
1040-
(buf_obj, byte_offset, bpe, ta_name)
1041-
};
1042-
let base = byte_offset.checked_add(idx.checked_mul(bpe)?)?;
1043-
let Value::Array(bytes) = buf_obj.borrow().get("__buffer_bytes__")?.clone() else {
1044-
return None;
1045-
};
1046-
let bb = bytes.borrow();
1047-
if base + bpe > bb.elements.len() {
1048-
return None;
1049-
}
1050-
Some(Self::decode_typed_element(&bb.elements, base, bpe, &ta_name))
1051-
}
1052-
1053-
fn decode_typed_element_from_raw(&self, raw: &[u8], bpe: usize, ta_name: &str) -> Value<'gc> {
1054-
let bytes: Vec<Value<'gc>> = raw.iter().map(|b| Value::Number(*b as f64)).collect();
1055-
Self::decode_typed_element(&bytes, 0, bpe, ta_name)
1056-
}
1057-
1058-
fn encode_typed_element_to_raw(&self, bpe: usize, ta_name: &str, value: &Value<'gc>) -> Option<Vec<u8>> {
1059-
let mut bytes = vec![Value::Number(0.0); bpe];
1060-
if ta_name == "BigInt64Array" || ta_name == "BigUint64Array" {
1061-
let Value::BigInt(bigint) = value else {
1062-
return None;
1063-
};
1064-
Self::encode_typed_element_bigint(&mut bytes, 0, ta_name, bigint);
1065-
} else {
1066-
Self::encode_typed_element(&mut bytes, 0, bpe, ta_name, to_number(value));
1067-
}
1068-
Some(bytes.into_iter().map(|v| to_number(&v) as u8).collect())
1069-
}
1070-
1071-
fn shared_or_local_ta_element(&self, arr: &ArrayHandle<'gc>, idx: usize) -> Value<'gc> {
1072-
self.shared_ta_read_element(arr, idx)
1073-
.or_else(|| self.local_ta_read_element(arr, idx))
1074-
.unwrap_or_else(|| arr.borrow().elements.get(idx).cloned().unwrap_or(Value::Undefined))
1075-
}
1076-
1077-
fn shared_atomic_rmw(
1078-
&mut self,
1079-
ctx: &GcContext<'gc>,
1080-
arr: &ArrayHandle<'gc>,
1081-
idx: usize,
1082-
ta_name: &str,
1083-
replacement_v: &Value<'gc>,
1084-
op: usize,
1085-
) -> Option<Value<'gc>> {
1086-
let (shared_id, byte_offset, bpe, _) = self.ensure_shared_ta_info(ctx, arr)?;
1087-
let base = byte_offset.checked_add(idx.checked_mul(bpe)?)?;
1088-
let is_bigint_ta = ta_name == "BigInt64Array" || ta_name == "BigUint64Array";
1089-
1090-
if is_bigint_ta {
1091-
let replacement_bi = self.value_to_bigint(ctx, replacement_v)?;
1092-
loop {
1093-
let old_raw = crate::js_agent::shared_buffer_read(shared_id, base, bpe)?;
1094-
let old_value = self.decode_typed_element_from_raw(&old_raw, bpe, ta_name);
1095-
let Value::BigInt(old_bi) = old_value.clone() else {
1096-
return Some(Value::Undefined);
1097-
};
1098-
1099-
let new_bi = match op {
1100-
BUILTIN_ATOMICS_ADD => old_bi.as_ref() + &replacement_bi,
1101-
BUILTIN_ATOMICS_SUB => old_bi.as_ref() - &replacement_bi,
1102-
BUILTIN_ATOMICS_AND => old_bi.as_ref() & &replacement_bi,
1103-
BUILTIN_ATOMICS_OR => old_bi.as_ref() | &replacement_bi,
1104-
BUILTIN_ATOMICS_XOR => old_bi.as_ref() ^ &replacement_bi,
1105-
BUILTIN_ATOMICS_EXCHANGE => replacement_bi.clone(),
1106-
_ => old_bi.as_ref().clone(),
1107-
};
1108-
let new_coerced = coerce_bigint_for_ta(&new_bi, ta_name);
1109-
let new_value = Value::BigInt(Box::new(new_coerced));
1110-
let new_raw = self.encode_typed_element_to_raw(bpe, ta_name, &new_value)?;
1111-
let actual_old = crate::js_agent::shared_buffer_compare_exchange(shared_id, base, &old_raw, &new_raw)?;
1112-
if actual_old == old_raw {
1113-
arr.borrow_mut(ctx).elements[idx] = new_value;
1114-
return Some(old_value);
1115-
}
1116-
}
1117-
}
1118-
1119-
let replacement_i32 = to_int32(to_number(replacement_v));
1120-
let replacement_f64 = replacement_i32 as f64;
1121-
loop {
1122-
let old_raw = crate::js_agent::shared_buffer_read(shared_id, base, bpe)?;
1123-
let old_value = self.decode_typed_element_from_raw(&old_raw, bpe, ta_name);
1124-
let old_f64 = to_number(&old_value);
1125-
1126-
let new_f64 = match op {
1127-
BUILTIN_ATOMICS_ADD => old_f64 + replacement_f64,
1128-
BUILTIN_ATOMICS_SUB => old_f64 - replacement_f64,
1129-
BUILTIN_ATOMICS_AND => (to_int32(old_f64) & replacement_i32) as f64,
1130-
BUILTIN_ATOMICS_OR => (to_int32(old_f64) | replacement_i32) as f64,
1131-
BUILTIN_ATOMICS_XOR => (to_int32(old_f64) ^ replacement_i32) as f64,
1132-
BUILTIN_ATOMICS_EXCHANGE => replacement_f64,
1133-
_ => old_f64,
1134-
};
1135-
let new_coerced = coerce_typed_array_value(new_f64, ta_name);
1136-
let new_value = Value::Number(new_coerced);
1137-
let new_raw = self.encode_typed_element_to_raw(bpe, ta_name, &new_value)?;
1138-
let actual_old = crate::js_agent::shared_buffer_compare_exchange(shared_id, base, &old_raw, &new_raw)?;
1139-
if actual_old == old_raw {
1140-
arr.borrow_mut(ctx).elements[idx] = new_value;
1141-
return Some(old_value);
1142-
}
1143-
}
1144-
}
1145-
1146971
fn make_shared_array_buffer_from_id(&mut self, ctx: &GcContext<'gc>, shared_id: u64) -> Option<Value<'gc>> {
1147972
let snapshot = crate::js_agent::shared_buffer_snapshot(shared_id)?;
1148973
let byte_length = snapshot.len();

src/core/vm/typedarray.rs

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,181 @@ impl<'gc> VM<'gc> {
257257
idx < arr.borrow().elements.len()
258258
}
259259

260+
pub(super) fn shared_ta_info(&self, arr: &ArrayHandle<'gc>) -> Option<(u64, usize, usize, String)> {
261+
let borrow = arr.borrow();
262+
let Value::Object(buf_obj) = borrow.props.get("__typedarray_buffer__")?.clone() else {
263+
return None;
264+
};
265+
let shared_id = self.shared_buffer_id_from_obj(&buf_obj)?;
266+
let byte_offset = borrow
267+
.props
268+
.get("__byte_offset__")
269+
.and_then(|v| if let Value::Number(n) = v { Some(*n as usize) } else { None })
270+
.unwrap_or(0);
271+
let bpe = borrow
272+
.props
273+
.get("__bytes_per_element__")
274+
.and_then(|v| {
275+
if let Value::Number(n) = v {
276+
Some((*n as usize).max(1))
277+
} else {
278+
None
279+
}
280+
})
281+
.unwrap_or(1);
282+
let ta_name = borrow.props.get("__typedarray_name__").map(value_to_string).unwrap_or_default();
283+
Some((shared_id, byte_offset, bpe, ta_name))
284+
}
285+
286+
pub(super) fn ensure_shared_ta_info(&mut self, ctx: &GcContext<'gc>, arr: &ArrayHandle<'gc>) -> Option<(u64, usize, usize, String)> {
287+
let buf_obj = {
288+
let borrow = arr.borrow();
289+
let Value::Object(buf_obj) = borrow.props.get("__typedarray_buffer__")?.clone() else {
290+
return None;
291+
};
292+
buf_obj
293+
};
294+
self.ensure_shared_buffer_id(ctx, &buf_obj)?;
295+
self.shared_ta_info(arr)
296+
}
297+
298+
pub(super) fn shared_ta_read_element(&self, arr: &ArrayHandle<'gc>, idx: usize) -> Option<Value<'gc>> {
299+
let (shared_id, byte_offset, bpe, ta_name) = self.shared_ta_info(arr)?;
300+
let base = byte_offset.checked_add(idx.checked_mul(bpe)?)?;
301+
let raw = crate::js_agent::shared_buffer_read(shared_id, base, bpe)?;
302+
let bytes: Vec<Value<'gc>> = raw.into_iter().map(|b| Value::Number(b as f64)).collect();
303+
Some(Self::decode_typed_element(&bytes, 0, bpe, &ta_name))
304+
}
305+
306+
pub(super) fn local_ta_read_element(&self, arr: &ArrayHandle<'gc>, idx: usize) -> Option<Value<'gc>> {
307+
let (buf_obj, byte_offset, bpe, ta_name) = {
308+
let borrow = arr.borrow();
309+
let Value::Object(buf_obj) = borrow.props.get("__typedarray_buffer__")?.clone() else {
310+
return None;
311+
};
312+
let byte_offset = borrow
313+
.props
314+
.get("__byte_offset__")
315+
.and_then(|v| if let Value::Number(n) = v { Some(*n as usize) } else { None })
316+
.unwrap_or(0);
317+
let bpe = borrow
318+
.props
319+
.get("__bytes_per_element__")
320+
.and_then(|v| {
321+
if let Value::Number(n) = v {
322+
Some((*n as usize).max(1))
323+
} else {
324+
None
325+
}
326+
})
327+
.unwrap_or(1);
328+
let ta_name = borrow.props.get("__typedarray_name__").map(value_to_string).unwrap_or_default();
329+
(buf_obj, byte_offset, bpe, ta_name)
330+
};
331+
let base = byte_offset.checked_add(idx.checked_mul(bpe)?)?;
332+
let Value::Array(bytes) = buf_obj.borrow().get("__buffer_bytes__")?.clone() else {
333+
return None;
334+
};
335+
let bb = bytes.borrow();
336+
if base + bpe > bb.elements.len() {
337+
return None;
338+
}
339+
Some(Self::decode_typed_element(&bb.elements, base, bpe, &ta_name))
340+
}
341+
342+
pub(super) fn decode_typed_element_from_raw(&self, raw: &[u8], bpe: usize, ta_name: &str) -> Value<'gc> {
343+
let bytes: Vec<Value<'gc>> = raw.iter().map(|b| Value::Number(*b as f64)).collect();
344+
Self::decode_typed_element(&bytes, 0, bpe, ta_name)
345+
}
346+
347+
pub(super) fn encode_typed_element_to_raw(&self, bpe: usize, ta_name: &str, value: &Value<'gc>) -> Option<Vec<u8>> {
348+
let mut bytes = vec![Value::Number(0.0); bpe];
349+
if ta_name == "BigInt64Array" || ta_name == "BigUint64Array" {
350+
let Value::BigInt(bigint) = value else {
351+
return None;
352+
};
353+
Self::encode_typed_element_bigint(&mut bytes, 0, ta_name, bigint);
354+
} else {
355+
Self::encode_typed_element(&mut bytes, 0, bpe, ta_name, to_number(value));
356+
}
357+
Some(bytes.into_iter().map(|v| to_number(&v) as u8).collect())
358+
}
359+
360+
pub(super) fn shared_or_local_ta_element(&self, arr: &ArrayHandle<'gc>, idx: usize) -> Value<'gc> {
361+
self.shared_ta_read_element(arr, idx)
362+
.or_else(|| self.local_ta_read_element(arr, idx))
363+
.unwrap_or_else(|| arr.borrow().elements.get(idx).cloned().unwrap_or(Value::Undefined))
364+
}
365+
366+
pub(super) fn shared_atomic_rmw(
367+
&mut self,
368+
ctx: &GcContext<'gc>,
369+
arr: &ArrayHandle<'gc>,
370+
idx: usize,
371+
ta_name: &str,
372+
replacement_v: &Value<'gc>,
373+
op: usize,
374+
) -> Option<Value<'gc>> {
375+
let (shared_id, byte_offset, bpe, _) = self.ensure_shared_ta_info(ctx, arr)?;
376+
let base = byte_offset.checked_add(idx.checked_mul(bpe)?)?;
377+
let is_bigint_ta = ta_name == "BigInt64Array" || ta_name == "BigUint64Array";
378+
379+
if is_bigint_ta {
380+
let replacement_bi = self.value_to_bigint(ctx, replacement_v)?;
381+
loop {
382+
let old_raw = crate::js_agent::shared_buffer_read(shared_id, base, bpe)?;
383+
let old_value = self.decode_typed_element_from_raw(&old_raw, bpe, ta_name);
384+
let Value::BigInt(old_bi) = old_value.clone() else {
385+
return Some(Value::Undefined);
386+
};
387+
388+
let new_bi = match op {
389+
BUILTIN_ATOMICS_ADD => old_bi.as_ref() + &replacement_bi,
390+
BUILTIN_ATOMICS_SUB => old_bi.as_ref() - &replacement_bi,
391+
BUILTIN_ATOMICS_AND => old_bi.as_ref() & &replacement_bi,
392+
BUILTIN_ATOMICS_OR => old_bi.as_ref() | &replacement_bi,
393+
BUILTIN_ATOMICS_XOR => old_bi.as_ref() ^ &replacement_bi,
394+
BUILTIN_ATOMICS_EXCHANGE => replacement_bi.clone(),
395+
_ => old_bi.as_ref().clone(),
396+
};
397+
let new_coerced = coerce_bigint_for_ta(&new_bi, ta_name);
398+
let new_value = Value::BigInt(Box::new(new_coerced));
399+
let new_raw = self.encode_typed_element_to_raw(bpe, ta_name, &new_value)?;
400+
let actual_old = crate::js_agent::shared_buffer_compare_exchange(shared_id, base, &old_raw, &new_raw)?;
401+
if actual_old == old_raw {
402+
arr.borrow_mut(ctx).elements[idx] = new_value;
403+
return Some(old_value);
404+
}
405+
}
406+
}
407+
408+
let replacement_i32 = to_int32(to_number(replacement_v));
409+
let replacement_f64 = replacement_i32 as f64;
410+
loop {
411+
let old_raw = crate::js_agent::shared_buffer_read(shared_id, base, bpe)?;
412+
let old_value = self.decode_typed_element_from_raw(&old_raw, bpe, ta_name);
413+
let old_f64 = to_number(&old_value);
414+
415+
let new_f64 = match op {
416+
BUILTIN_ATOMICS_ADD => old_f64 + replacement_f64,
417+
BUILTIN_ATOMICS_SUB => old_f64 - replacement_f64,
418+
BUILTIN_ATOMICS_AND => (to_int32(old_f64) & replacement_i32) as f64,
419+
BUILTIN_ATOMICS_OR => (to_int32(old_f64) | replacement_i32) as f64,
420+
BUILTIN_ATOMICS_XOR => (to_int32(old_f64) ^ replacement_i32) as f64,
421+
BUILTIN_ATOMICS_EXCHANGE => replacement_f64,
422+
_ => old_f64,
423+
};
424+
let new_coerced = coerce_typed_array_value(new_f64, ta_name);
425+
let new_value = Value::Number(new_coerced);
426+
let new_raw = self.encode_typed_element_to_raw(bpe, ta_name, &new_value)?;
427+
let actual_old = crate::js_agent::shared_buffer_compare_exchange(shared_id, base, &old_raw, &new_raw)?;
428+
if actual_old == old_raw {
429+
arr.borrow_mut(ctx).elements[idx] = new_value;
430+
return Some(old_value);
431+
}
432+
}
433+
}
434+
260435
pub(super) fn typedarray_handle_host_fn(
261436
&mut self,
262437
ctx: &GcContext<'gc>,

0 commit comments

Comments
 (0)