public static EcmaValue Wait(TypedArray array, EcmaValue index, EcmaValue value, EcmaValue timeout) { int pos = ValidateWaitableArrayAndIndex(array, index); bool isInt32 = array.ArrayKind == TypedArrayKind.Int32Array; long longValue = isInt32 ? value.ToInt32() : value.ToBigInt64().ToInt64(); timeout = timeout.ToNumber(); if (!RuntimeExecution.Current.CanSuspend) { throw new EcmaTypeErrorException("Atomics.wait cannot be called in this context"); } bool comparandEquals, result; int milliseconds = timeout.IsNaN || timeout > Int32.MaxValue ? -1 : timeout < 0 ? 0 : timeout.ToInt32(); SharedArrayBuffer buffer = (SharedArrayBuffer)array.Buffer; if (isInt32) { result = buffer.Wait(array.GetByteOffset(pos), (int)longValue, milliseconds, out comparandEquals); } else { result = buffer.Wait(array.GetByteOffset(pos), longValue, milliseconds, out comparandEquals); } return(result ? "ok" : comparandEquals ? "timed-out" : "not-equal"); }
public static EcmaValue Notify(TypedArray array, EcmaValue index, EcmaValue count) { int pos = ValidateWaitableArrayAndIndex(array, index); count = count == default ? Int32.MaxValue : count.ToNumber(); int countValue = count.IsNaN || count <= 0 ? 0 : count > Int32.MaxValue ? Int32.MaxValue : count.ToInt32(); SharedArrayBuffer buffer = (SharedArrayBuffer)array.Buffer; return(buffer.Notify(array.GetByteOffset(pos), countValue)); }
private static EcmaValue DoAtomicOperation(TypedArray array, EcmaValue index, Operation operation, EcmaValue value, EcmaValue replacement) { int i = ValidateArrayAndIndex(array, index); value = value.ToNumber(); replacement = replacement.ToNumber(); long offset = array.GetByteOffset(i); int[] buffer = array.Buffer.Int32Array; int bufferIndex = (int)(offset >> 2); int bytesPerElement = array.ElementSize; int operand = value.ToInt32(); int bitShift = 0; int mask = -1; if (bytesPerElement != 4) { int byteShift = (int)(offset % 4); if (byteShift != 0 && !BitConverter.IsLittleEndian) { byteShift = 4 - byteShift; } bitShift = byteShift * 8; operand <<= bitShift; mask = (bytesPerElement == 2 ? shortMask : byteMask)[byteShift]; } else { int result; switch (operation) { case Operation.CompareExchange: result = Interlocked.CompareExchange(ref buffer[bufferIndex], replacement.ToInt32(), operand); break; case Operation.Exchange: result = Interlocked.Exchange(ref buffer[bufferIndex], operand); break; case Operation.Add: result = unchecked (Interlocked.Add(ref buffer[bufferIndex], operand) - operand); break; case Operation.Sub: result = unchecked (Interlocked.Add(ref buffer[bufferIndex], -operand) + operand); break; default: goto fallback; } return(array.ArrayKind == TypedArrayKind.Uint32Array ? (EcmaValue)(uint)result : result); } fallback: while (true) { int curValue = buffer[bufferIndex]; int newValue = curValue; switch (operation) { case Operation.Or: newValue |= operand; break; case Operation.And: newValue &= operand; break; case Operation.Xor: newValue ^= operand; break; case Operation.Add: newValue = unchecked (curValue + operand); break; case Operation.Sub: newValue = unchecked (curValue - operand); break; case Operation.CompareExchange: newValue = (curValue & mask) == (operand & mask) ? replacement.ToInt32() << bitShift : curValue; break; case Operation.Exchange: newValue = operand; break; } if (bytesPerElement != 4) { newValue = (curValue & ~mask) | (newValue & mask); } if (curValue == Interlocked.CompareExchange(ref buffer[bufferIndex], newValue, curValue)) { int result = (curValue & mask) >> bitShift; switch (array.ArrayKind) { case TypedArrayKind.Int8Array: return((sbyte)result); case TypedArrayKind.Uint8Array: return((byte)result); case TypedArrayKind.Int16Array: return((short)result); case TypedArrayKind.Uint16Array: return((ushort)result); case TypedArrayKind.Uint32Array: return((uint)result); } return(result); } } }