// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(function(global, utils) {
"use strict";
%CheckIsBootstrapping();
// -------------------------------------------------------------------
// Imports
var GlobalObject = global.Object;
var MakeRangeError;
var MakeTypeError;
var MaxSimple;
var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
utils.Import(function(from) {
MakeTypeError = from.MakeTypeError;
MakeRangeError = from.MakeRangeError;
MaxSimple = from.MaxSimple;
});
// -------------------------------------------------------------------
function CheckSharedIntegerTypedArray(ia) {
if (!%IsSharedIntegerTypedArray(ia)) {
throw MakeTypeError(kNotIntegerSharedTypedArray, ia);
}
}
function CheckSharedInteger32TypedArray(ia) {
CheckSharedIntegerTypedArray(ia);
if (!%IsSharedInteger32TypedArray(ia)) {
throw MakeTypeError(kNotInt32SharedTypedArray, ia);
}
}
// https://tc39.github.io/ecmascript_sharedmem/shmem.html#Atomics.ValidateAtomicAccess
function ValidateIndex(index, length) {
var numberIndex = TO_NUMBER(index);
var accessIndex = TO_INTEGER(numberIndex);
if (numberIndex !== accessIndex) {
throw MakeRangeError(kInvalidAtomicAccessIndex);
}
if (accessIndex < 0 || accessIndex >= length) {
throw MakeRangeError(kInvalidAtomicAccessIndex);
}
return accessIndex;
}
//-------------------------------------------------------------------
function AtomicsCompareExchangeJS(sta, index, oldValue, newValue) {
CheckSharedIntegerTypedArray(sta);
index = ValidateIndex(index, %_TypedArrayGetLength(sta));
oldValue = TO_NUMBER(oldValue);
newValue = TO_NUMBER(newValue);
return %_AtomicsCompareExchange(sta, index, oldValue, newValue);
}
function AtomicsAddJS(ia, index, value) {
CheckSharedIntegerTypedArray(ia);
index = ValidateIndex(index, %_TypedArrayGetLength(ia));
value = TO_NUMBER(value);
return %_AtomicsAdd(ia, index, value);
}
function AtomicsSubJS(ia, index, value) {
CheckSharedIntegerTypedArray(ia);
index = ValidateIndex(index, %_TypedArrayGetLength(ia));
value = TO_NUMBER(value);
return %_AtomicsSub(ia, index, value);
}
function AtomicsAndJS(ia, index, value) {
CheckSharedIntegerTypedArray(ia);
index = ValidateIndex(index, %_TypedArrayGetLength(ia));
value = TO_NUMBER(value);
return %_AtomicsAnd(ia, index, value);
}
function AtomicsOrJS(ia, index, value) {
CheckSharedIntegerTypedArray(ia);
index = ValidateIndex(index, %_TypedArrayGetLength(ia));
value = TO_NUMBER(value);
return %_AtomicsOr(ia, index, value);
}
function AtomicsXorJS(ia, index, value) {
CheckSharedIntegerTypedArray(ia);
index = ValidateIndex(index, %_TypedArrayGetLength(ia));
value = TO_NUMBER(value);
return %_AtomicsXor(ia, index, value);
}
function AtomicsExchangeJS(ia, index, value) {
CheckSharedIntegerTypedArray(ia);
index = ValidateIndex(index, %_TypedArrayGetLength(ia));
value = TO_NUMBER(value);
return %_AtomicsExchange(ia, index, value);
}
function AtomicsIsLockFreeJS(size) {
return %_AtomicsIsLockFree(size);
}
// Futexes
function AtomicsFutexWaitJS(ia, index, value, timeout) {
CheckSharedInteger32TypedArray(ia);
index = ValidateIndex(index, %_TypedArrayGetLength(ia));
if (IS_UNDEFINED(timeout)) {
timeout = INFINITY;
} else {
timeout = TO_NUMBER(timeout);
if (NUMBER_IS_NAN(timeout)) {
timeout = INFINITY;
} else {
timeout = MaxSimple(0, timeout);
}
}
return %AtomicsFutexWait(ia, index, value, timeout);
}
function AtomicsFutexWakeJS(ia, index, count) {
CheckSharedInteger32TypedArray(ia);
index = ValidateIndex(index, %_TypedArrayGetLength(ia));
count = MaxSimple(0, TO_INTEGER(count));
return %AtomicsFutexWake(ia, index, count);
}
function AtomicsFutexWakeOrRequeueJS(ia, index1, count, value, index2) {
CheckSharedInteger32TypedArray(ia);
index1 = ValidateIndex(index1, %_TypedArrayGetLength(ia));
count = MaxSimple(0, TO_INTEGER(count));
value = TO_INT32(value);
index2 = ValidateIndex(index2, %_TypedArrayGetLength(ia));
if (index1 < 0 || index1 >= %_TypedArrayGetLength(ia) ||
index2 < 0 || index2 >= %_TypedArrayGetLength(ia)) {
return UNDEFINED;
}
return %AtomicsFutexWakeOrRequeue(ia, index1, count, value, index2);
}
// -------------------------------------------------------------------
var Atomics = global.Atomics;
// The Atomics global is defined by the bootstrapper.
%AddNamedProperty(Atomics, toStringTagSymbol, "Atomics", READ_ONLY | DONT_ENUM);
// These must match the values in src/futex-emulation.h
utils.InstallConstants(Atomics, [
"OK", 0,
"NOTEQUAL", -1,
"TIMEDOUT", -2,
]);
utils.InstallFunctions(Atomics, DONT_ENUM, [
// TODO(binji): remove the rest of the (non futex) Atomics functions as they
// become builtins.
"compareExchange", AtomicsCompareExchangeJS,
"add", AtomicsAddJS,
"sub", AtomicsSubJS,
"and", AtomicsAndJS,
"or", AtomicsOrJS,
"xor", AtomicsXorJS,
"exchange", AtomicsExchangeJS,
"isLockFree", AtomicsIsLockFreeJS,
"futexWait", AtomicsFutexWaitJS,
"futexWake", AtomicsFutexWakeJS,
"futexWakeOrRequeue", AtomicsFutexWakeOrRequeueJS,
]);
})