22// License, v. 2.0. If a copy of the MPL was not distributed with this
33// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44
5+ use ecmascript_atomics:: Ordering ;
6+
57use crate :: {
68 ecmascript:: {
79 abstract_operations:: type_conversion:: {
@@ -10,7 +12,7 @@ use crate::{
1012 builders:: ordinary_object_builder:: OrdinaryObjectBuilder ,
1113 builtins:: {
1214 ArgumentsList , Behaviour , Builtin ,
13- array_buffer:: get_modify_set_value_in_buffer,
15+ array_buffer:: { get_modify_set_value_in_buffer, get_value_from_buffer } ,
1416 indexed_collections:: typed_array_objects:: abstract_operations:: {
1517 TypedArrayAbstractOperations , TypedArrayWithBufferWitnessRecords ,
1618 make_typed_array_with_buffer_witness_record, validate_typed_array,
@@ -219,13 +221,92 @@ impl AtomicsObject {
219221 Err ( agent. todo ( "Atomics.isLockFree" , gc. into_nogc ( ) ) )
220222 }
221223
224+ /// ### [25.4.9 Atomics.load ( typedArray, index )](https://tc39.es/ecma262/#sec-atomics.load)
222225 fn load < ' gc > (
223226 agent : & mut Agent ,
224227 _this_value : Value ,
225- _arguments : ArgumentsList ,
226- gc : GcScope < ' gc , ' _ > ,
228+ arguments : ArgumentsList ,
229+ mut gc : GcScope < ' gc , ' _ > ,
227230 ) -> JsResult < ' gc , Value < ' gc > > {
228- Err ( agent. todo ( "Atomics.load" , gc. into_nogc ( ) ) )
231+ let arguments = arguments. bind ( gc. nogc ( ) ) ;
232+ let typed_array = arguments. get ( 0 ) ;
233+ let index = arguments. get ( 1 ) ;
234+ // 1. Let byteIndexInBuffer be ? ValidateAtomicAccessOnIntegerTypedArray(typedArray, index).
235+ let ta_record = validate_typed_array (
236+ agent,
237+ typed_array,
238+ ecmascript_atomics:: Ordering :: Unordered ,
239+ gc. nogc ( ) ,
240+ )
241+ . unbind ( ) ?
242+ . bind ( gc. nogc ( ) ) ;
243+ // a. Let type be TypedArrayElementType(typedArray).
244+ // b. If IsUnclampedIntegerElementType(type) is false and
245+ // IsBigIntElementType(type) is false, throw a TypeError exception.
246+ if !ta_record. object . is_integer ( ) {
247+ return Err ( agent. throw_exception_with_static_message (
248+ ExceptionType :: TypeError ,
249+ "cannot use TypedArray in Atomics" ,
250+ gc. into_nogc ( ) ,
251+ ) ) ;
252+ }
253+ // 1. Let length be TypedArrayLength(taRecord).
254+ let length = ta_record. typed_array_length ( agent) ;
255+ let ( byte_index_in_buffer, typed_array) = if let Value :: Integer ( index) = index {
256+ // 7. Let offset be typedArray.[[ByteOffset]].
257+ let typed_array = ta_record. object . bind ( gc. nogc ( ) ) ;
258+ // 2. Let accessIndex be ? ToIndex(requestIndex).
259+ let access_index = validate_index ( agent, index. into_i64 ( ) , gc. nogc ( ) ) . unbind ( ) ?;
260+ // 3. If accessIndex ≥ length, throw a RangeError exception.
261+ if access_index >= length as u64 {
262+ return Err ( agent. throw_exception_with_static_message (
263+ ExceptionType :: RangeError ,
264+ "accessIndex out of bounds" ,
265+ gc. into_nogc ( ) ,
266+ ) ) ;
267+ }
268+ let access_index = access_index as usize ;
269+ // 5. Let typedArray be taRecord.[[Object]].
270+ let offset = typed_array. byte_offset ( agent) ;
271+ let byte_index_in_buffer =
272+ offset + access_index * typed_array. typed_array_element_size ( ) ;
273+ ( byte_index_in_buffer, typed_array)
274+ } else {
275+ // 2. Perform ? RevalidateAtomicAccess(typedArray, byteIndexInBuffer).
276+ atomic_load_slow (
277+ agent,
278+ ta_record. unbind ( ) ,
279+ index. unbind ( ) ,
280+ length,
281+ gc. reborrow ( ) ,
282+ )
283+ . unbind ( ) ?
284+ . bind ( gc. nogc ( ) )
285+ } ;
286+ let typed_array = typed_array. unbind ( ) ;
287+ let gc = gc. into_nogc ( ) ;
288+ let typed_array = typed_array. bind ( gc) ;
289+ // 3. Let buffer be typedArray.[[ViewedArrayBuffer]].
290+ let buffer = typed_array. viewed_array_buffer ( agent) ;
291+ // 4. Let elementType be TypedArrayElementType(typedArray).
292+ // 5. Return GetValueFromBuffer(buffer, byteIndexInBuffer, elementType, true, seq-cst).
293+ Ok ( for_any_typed_array ! (
294+ typed_array,
295+ _t,
296+ {
297+ get_value_from_buffer:: <ElementType >(
298+ agent,
299+ buffer,
300+ byte_index_in_buffer,
301+ true ,
302+ Ordering :: SeqCst ,
303+ None ,
304+ gc,
305+ )
306+ } ,
307+ ElementType
308+ )
309+ . into_value ( ) )
229310 }
230311
231312 fn or < ' gc > (
@@ -671,3 +752,60 @@ fn atomic_read_modify_write_slow<'gc>(
671752 }
672753 Ok ( ( byte_index_in_buffer, typed_array, v) )
673754}
755+
756+ #[ inline( never) ]
757+ #[ cold]
758+ fn atomic_load_slow < ' gc > (
759+ agent : & mut Agent ,
760+ ta_record : TypedArrayWithBufferWitnessRecords ,
761+ index : Value ,
762+ length : usize ,
763+ mut gc : GcScope < ' gc , ' _ > ,
764+ ) -> JsResult < ' gc , ( usize , AnyTypedArray < ' gc > ) > {
765+ let mut ta_record = ta_record. bind ( gc. nogc ( ) ) ;
766+ let index = index. bind ( gc. nogc ( ) ) ;
767+ let mut revalidate = false ;
768+
769+ // 2. Let accessIndex be ? ToIndex(requestIndex).
770+ let access_index =
771+ if let Some ( index) = try_result_into_js ( try_to_index ( agent, index, gc. nogc ( ) ) ) . unbind ( ) ? {
772+ index
773+ } else {
774+ let ta = ta_record. object . scope ( agent, gc. nogc ( ) ) ;
775+ let cached_buffer_byte_length = ta_record. cached_buffer_byte_length ;
776+ let access_index = to_index ( agent, index. unbind ( ) , gc. reborrow ( ) ) . unbind ( ) ?;
777+ revalidate = true ;
778+ // SAFETY: not shared.
779+ ta_record = unsafe {
780+ TypedArrayWithBufferWitnessRecords {
781+ object : ta. take ( agent) ,
782+ cached_buffer_byte_length,
783+ }
784+ } ;
785+ access_index
786+ } ;
787+ // 3. Assert: accessIndex ≥ 0.
788+ // 4. If accessIndex ≥ length, throw a RangeError exception.
789+ if access_index >= length as u64 {
790+ return Err ( agent. throw_exception_with_static_message (
791+ ExceptionType :: RangeError ,
792+ "accessIndex out of bounds" ,
793+ gc. into_nogc ( ) ,
794+ ) ) ;
795+ }
796+ let access_index = access_index as usize ;
797+ // 5. Let typedArray be taRecord.[[Object]].
798+ // 6. Let elementSize be TypedArrayElementSize(typedArray).
799+ // 7. Let offset be typedArray.[[ByteOffset]].
800+ let offset = ta_record. object . byte_offset ( agent) ;
801+ // 8. Return (accessIndex × elementSize) + offset.
802+ let byte_index_in_buffer = offset + access_index * ta_record. object . typed_array_element_size ( ) ;
803+ let typed_array = ta_record. object . unbind ( ) ;
804+ let gc = gc. into_nogc ( ) ;
805+ let typed_array = typed_array. bind ( gc) ;
806+ if revalidate {
807+ // 2. Perform ? RevalidateAtomicAccess(typedArray, byteIndexInBuffer).
808+ revalidate_atomic_access ( agent, typed_array, byte_index_in_buffer, gc) ?;
809+ }
810+ Ok ( ( byte_index_in_buffer, typed_array) )
811+ }
0 commit comments