Skip to content

Commit b38072f

Browse files
committed
Implement SharedArrayBuffer, Atomics and refactor TypedArray native methods
- Refactor src/js_typedarray.rs to use Value based arguments for native handlers - Implement SharedArrayBuffer constructor and prototype with byteLength accessor - Implement Atomics object and methods including wait/notify - Update TypedArray and DataView prototypes to use Value::Property getters - Add accessor handlers for ArrayBuffer and TypedArray properties - Integrate Atomics and accessor dispatch in src/core/eval.rs
1 parent 227fa2f commit b38072f

File tree

6 files changed

+487
-285
lines changed

6 files changed

+487
-285
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
2+
try {
3+
console.log("Testing SharedArrayBuffer...");
4+
let sab = new SharedArrayBuffer(1024);
5+
6+
// Check byteLength
7+
if (sab.byteLength !== 1024) {
8+
throw new Error("byteLength is incorrect: " + sab.byteLength);
9+
}
10+
console.log("byteLength OK");
11+
12+
// Check prototype
13+
if (!(sab instanceof SharedArrayBuffer)) {
14+
throw new Error("instanceof SharedArrayBuffer failed");
15+
}
16+
console.log("instanceof OK");
17+
18+
if (sab instanceof ArrayBuffer) {
19+
// SharedArrayBuffer is NOT an ArrayBuffer
20+
throw new Error("SharedArrayBuffer should not be instanceof ArrayBuffer");
21+
}
22+
console.log("Not instanceof ArrayBuffer OK");
23+
24+
// Check usage with TypedArray
25+
let i32 = new Int32Array(sab);
26+
if (i32.byteLength !== 1024) {
27+
throw new Error("TypedArray byteLength incorrect: " + i32.byteLength);
28+
}
29+
console.log("Int32Array on SAB OK");
30+
31+
// Check Atomics
32+
Atomics.store(i32, 0, 42);
33+
let val = Atomics.load(i32, 0);
34+
if (val !== 42) {
35+
throw new Error("Atomics store/load failed: " + val);
36+
}
37+
console.log("Atomics basic OK");
38+
39+
// Check Atomics.wait (timeout)
40+
// Value at index 0 is 42. verification:
41+
if (Atomics.load(i32, 0) !== 42) {
42+
throw new Error("Value check failed before wait");
43+
}
44+
console.log("Testing wait (timeout expected)...");
45+
let initialTime = Date.now();
46+
let waitResult = Atomics.wait(i32, 0, 42, 100); // 100ms timeout
47+
let duration = Date.now() - initialTime;
48+
49+
// Note: implementation might not be high precision, but should be > 0.
50+
console.log("Wait result:", waitResult, "Duration:", duration);
51+
52+
if (waitResult !== "timed-out") {
53+
throw new Error("Atomics.wait expected 'timed-out', got: " + waitResult);
54+
}
55+
56+
// Check Atomics.notify (0 waiters)
57+
let notifyResult = Atomics.notify(i32, 0, 1);
58+
if (notifyResult !== 0) {
59+
throw new Error("Atomics.notify expected 0, got: " + notifyResult);
60+
}
61+
console.log("Atomics wait/notify OK");
62+
63+
console.log("SharedArrayBuffer Final Test Passed!");
64+
65+
} catch (e) {
66+
console.log("Test Failed:");
67+
console.log(e);
68+
}

js-scripts/test_typedarray_constructors.js renamed to js-scripts/typedarray_test_1.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
1+
"use strict";
2+
3+
function assert(condition, message) {
4+
if (!condition) {
5+
throw new Error(message);
6+
}
7+
}
8+
19
// Test TypedArray constructors from JavaScript
210
console.log("Testing TypedArray constructors...");
311

412
// Test ArrayBuffer
513
let buffer = new ArrayBuffer(16);
614
console.log("ArrayBuffer created with length:", buffer.byteLength);
15+
assert(buffer.byteLength === 16, "ArrayBuffer length should be 16");
716

817
// Test DataView
918
let view = new DataView(buffer);
@@ -12,26 +21,34 @@ console.log("DataView created");
1221
// Test TypedArrays
1322
let int8Array = new Int8Array(10);
1423
console.log("Int8Array created with length:", int8Array.length);
24+
assert(int8Array.length === 10, "Int8Array length should be 10");
1525

1626
let uint8Array = new Uint8Array(10);
1727
console.log("Uint8Array created with length:", uint8Array.length);
28+
assert(uint8Array.length === 10, "Uint8Array length should be 10");
1829

1930
let int16Array = new Int16Array(5);
2031
console.log("Int16Array created with length:", int16Array.length);
32+
assert(int16Array.length === 5, "Int16Array length should be 5");
2133

2234
let uint16Array = new Uint16Array(5);
2335
console.log("Uint16Array created with length:", uint16Array.length);
36+
assert(uint16Array.length === 5, "Uint16Array length should be 5");
2437

2538
let int32Array = new Int32Array(3);
2639
console.log("Int32Array created with length:", int32Array.length);
40+
assert(int32Array.length === 3, "Int32Array length should be 3");
2741

2842
let uint32Array = new Uint32Array(3);
2943
console.log("Uint32Array created with length:", uint32Array.length);
44+
assert(uint32Array.length === 3, "Uint32Array length should be 3");
3045

3146
let float32Array = new Float32Array(4);
3247
console.log("Float32Array created with length:", float32Array.length);
48+
assert(float32Array.length === 4, "Float32Array length should be 4");
3349

3450
let float64Array = new Float64Array(2);
3551
console.log("Float64Array created with length:", float64Array.length);
52+
assert(float64Array.length === 2, "Float64Array length should be 2");
3653

3754
console.log("All TypedArray constructors work!");

src/core/eval.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2151,6 +2151,14 @@ pub fn evaluate_expr<'gc>(mc: &MutationContext<'gc>, env: &JSObjectDataPtr<'gc>,
21512151
return Ok(crate::js_weakset::handle_weakset_constructor(mc, &eval_args, env)?);
21522152
} else if name == &crate::unicode::utf8_to_utf16("Set") {
21532153
return Ok(crate::js_set::handle_set_constructor(mc, &eval_args, env)?);
2154+
} else if name == &crate::unicode::utf8_to_utf16("ArrayBuffer") {
2155+
return Ok(crate::js_typedarray::handle_arraybuffer_constructor(mc, &eval_args, env)?);
2156+
} else if name == &crate::unicode::utf8_to_utf16("SharedArrayBuffer") {
2157+
return Ok(crate::js_typedarray::handle_sharedarraybuffer_constructor(mc, &eval_args, env)?);
2158+
} else if name == &crate::unicode::utf8_to_utf16("DataView") {
2159+
return Ok(crate::js_typedarray::handle_dataview_constructor(mc, &eval_args, env)?);
2160+
} else if name == &crate::unicode::utf8_to_utf16("TypedArray") {
2161+
return Ok(crate::js_typedarray::handle_typedarray_constructor(mc, &obj, &eval_args, env)?);
21542162
}
21552163
}
21562164
}
@@ -2710,6 +2718,66 @@ fn call_native_function<'gc>(
27102718
}
27112719
}
27122720
}
2721+
2722+
if name.starts_with("DataView.prototype.") {
2723+
if let Some(method) = name.strip_prefix("DataView.prototype.") {
2724+
let this_v = this_val.clone().unwrap_or(Value::Undefined);
2725+
if let Value::Object(obj) = this_v {
2726+
return Ok(Some(
2727+
crate::js_typedarray::handle_dataview_method(mc, &obj, method, args, env).map_err(EvalError::Js)?,
2728+
));
2729+
} else {
2730+
return Err(EvalError::Js(raise_eval_error!("TypeError: DataView method called on non-object")));
2731+
}
2732+
}
2733+
}
2734+
2735+
if name.starts_with("Atomics.") {
2736+
if let Some(method) = name.strip_prefix("Atomics.") {
2737+
return Ok(Some(
2738+
crate::js_typedarray::handle_atomics_method(mc, method, args, env).map_err(EvalError::Js)?,
2739+
));
2740+
}
2741+
}
2742+
2743+
if name == "ArrayBuffer.prototype.byteLength" {
2744+
let this_v = this_val.clone().unwrap_or(Value::Undefined);
2745+
if let Value::Object(obj) = this_v {
2746+
return Ok(Some(
2747+
crate::js_typedarray::handle_arraybuffer_accessor(mc, &obj, "byteLength").map_err(EvalError::Js)?,
2748+
));
2749+
} else {
2750+
return Err(EvalError::Js(raise_eval_error!(
2751+
"TypeError: ArrayBuffer.prototype.byteLength called on non-object"
2752+
)));
2753+
}
2754+
}
2755+
2756+
if name == "SharedArrayBuffer.prototype.byteLength" {
2757+
let this_v = this_val.clone().unwrap_or(Value::Undefined);
2758+
if let Value::Object(obj) = this_v {
2759+
return Ok(Some(
2760+
crate::js_typedarray::handle_arraybuffer_accessor(mc, &obj, "byteLength").map_err(EvalError::Js)?,
2761+
));
2762+
} else {
2763+
return Err(EvalError::Js(raise_eval_error!(
2764+
"TypeError: SharedArrayBuffer.prototype.byteLength called on non-object"
2765+
)));
2766+
}
2767+
}
2768+
2769+
if let Some(prop) = name.strip_prefix("TypedArray.prototype.") {
2770+
let this_v = this_val.clone().unwrap_or(Value::Undefined);
2771+
if let Value::Object(obj) = this_v {
2772+
return Ok(Some(
2773+
crate::js_typedarray::handle_typedarray_accessor(mc, &obj, prop).map_err(EvalError::Js)?,
2774+
));
2775+
} else {
2776+
return Err(EvalError::Js(raise_eval_error!(
2777+
"TypeError: TypedArray accessor called on non-object"
2778+
)));
2779+
}
2780+
}
27132781
Ok(None)
27142782
}
27152783

src/core/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ pub fn initialize_global_constructors<'gc>(mc: &MutationContext<'gc>, env: &JSOb
7474
initialize_regexp(mc, env)?;
7575
// Initialize Date constructor and prototype
7676
initialize_date(mc, env)?;
77+
crate::js_typedarray::initialize_typedarray(mc, env)?;
7778
initialize_bigint(mc, env)?;
7879
initialize_json(mc, env)?;
7980
initialize_map(mc, env)?;

0 commit comments

Comments
 (0)