--- a/js/src/NamespaceImports.h
+++ b/js/src/NamespaceImports.h
@@ -33,28 +33,30 @@ class UTF8CharsZ;
class AutoValueVector;
class AutoIdVector;
class AutoObjectVector;
using ValueVector = JS::GCVector<JS::Value>;
using IdVector = JS::GCVector<jsid>;
using ScriptVector = JS::GCVector<JSScript*>;
-template<typename K, typename V> class AutoHashMapRooter;
-template<typename T> class AutoHashSetRooter;
+template<typename K, typename V>
+class AutoHashMapRooter;
+template<typename T>
+class AutoHashSetRooter;
class MOZ_STACK_CLASS SourceBufferHolder;
class HandleValueArray;
class ObjectOpResult;
class PropertyResult;
class Symbol;
-enum class SymbolCode: uint32_t;
+enum class SymbolCode : uint32_t;
} // namespace JS
// Do the importing.
namespace js {
using JS::Value;
using JS::BooleanValue;
--- a/js/src/builtin/AtomicsObject.cpp
+++ b/js/src/builtin/AtomicsObject.cpp
@@ -64,20 +64,17 @@
#include "vm/Time.h"
#include "vm/TypedArrayObject.h"
#include "wasm/WasmInstance.h"
#include "jsobjinlines.h"
using namespace js;
-const Class AtomicsObject::class_ = {
- "Atomics",
- JSCLASS_HAS_CACHED_PROTO(JSProto_Atomics)
-};
+const Class AtomicsObject::class_ = { "Atomics", JSCLASS_HAS_CACHED_PROTO(JSProto_Atomics) };
static bool
ReportBadArrayType(JSContext* cx)
{
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ATOMICS_BAD_ARRAY);
return false;
}
@@ -93,18 +90,17 @@ ReportOutOfRange(JSContext* cx)
static bool
ReportCannotWait(JSContext* cx)
{
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ATOMICS_WAIT_NOT_ALLOWED);
return false;
}
static bool
-GetSharedTypedArray(JSContext* cx, HandleValue v,
- MutableHandle<TypedArrayObject*> viewp)
+GetSharedTypedArray(JSContext* cx, HandleValue v, MutableHandle<TypedArrayObject*> viewp)
{
if (!v.isObject())
return ReportBadArrayType(cx);
if (!v.toObject().is<TypedArrayObject>())
return ReportBadArrayType(cx);
viewp.set(&v.toObject().as<TypedArrayObject>());
if (!viewp->isSharedMemory())
return ReportBadArrayType(cx);
@@ -119,66 +115,70 @@ GetTypedArrayIndex(JSContext* cx, Handle
return false;
if (index >= view->length())
return ReportOutOfRange(cx);
*offset = uint32_t(index);
return true;
}
static int32_t
-CompareExchange(Scalar::Type viewType, int32_t oldCandidate, int32_t newCandidate,
- SharedMem<void*> viewData, uint32_t offset, bool* badArrayType = nullptr)
+CompareExchange(Scalar::Type viewType,
+ int32_t oldCandidate,
+ int32_t newCandidate,
+ SharedMem<void*> viewData,
+ uint32_t offset,
+ bool* badArrayType = nullptr)
{
switch (viewType) {
- case Scalar::Int8: {
- int8_t oldval = (int8_t)oldCandidate;
- int8_t newval = (int8_t)newCandidate;
- oldval = jit::AtomicOperations::compareExchangeSeqCst(viewData.cast<int8_t*>() + offset,
- oldval, newval);
- return oldval;
- }
- case Scalar::Uint8: {
- uint8_t oldval = (uint8_t)oldCandidate;
- uint8_t newval = (uint8_t)newCandidate;
- oldval = jit::AtomicOperations::compareExchangeSeqCst(viewData.cast<uint8_t*>() + offset,
- oldval, newval);
- return oldval;
- }
- case Scalar::Int16: {
- int16_t oldval = (int16_t)oldCandidate;
- int16_t newval = (int16_t)newCandidate;
- oldval = jit::AtomicOperations::compareExchangeSeqCst(viewData.cast<int16_t*>() + offset,
- oldval, newval);
- return oldval;
- }
- case Scalar::Uint16: {
- uint16_t oldval = (uint16_t)oldCandidate;
- uint16_t newval = (uint16_t)newCandidate;
- oldval = jit::AtomicOperations::compareExchangeSeqCst(viewData.cast<uint16_t*>() + offset,
- oldval, newval);
- return oldval;
- }
- case Scalar::Int32: {
- int32_t oldval = oldCandidate;
- int32_t newval = newCandidate;
- oldval = jit::AtomicOperations::compareExchangeSeqCst(viewData.cast<int32_t*>() + offset,
- oldval, newval);
- return oldval;
- }
- case Scalar::Uint32: {
- uint32_t oldval = (uint32_t)oldCandidate;
- uint32_t newval = (uint32_t)newCandidate;
- oldval = jit::AtomicOperations::compareExchangeSeqCst(viewData.cast<uint32_t*>() + offset,
- oldval, newval);
- return (int32_t)oldval;
- }
- default:
- if (badArrayType)
- *badArrayType = true;
- return 0;
+ case Scalar::Int8: {
+ int8_t oldval = (int8_t)oldCandidate;
+ int8_t newval = (int8_t)newCandidate;
+ oldval = jit::AtomicOperations::compareExchangeSeqCst(
+ viewData.cast<int8_t*>() + offset, oldval, newval);
+ return oldval;
+ }
+ case Scalar::Uint8: {
+ uint8_t oldval = (uint8_t)oldCandidate;
+ uint8_t newval = (uint8_t)newCandidate;
+ oldval = jit::AtomicOperations::compareExchangeSeqCst(
+ viewData.cast<uint8_t*>() + offset, oldval, newval);
+ return oldval;
+ }
+ case Scalar::Int16: {
+ int16_t oldval = (int16_t)oldCandidate;
+ int16_t newval = (int16_t)newCandidate;
+ oldval = jit::AtomicOperations::compareExchangeSeqCst(
+ viewData.cast<int16_t*>() + offset, oldval, newval);
+ return oldval;
+ }
+ case Scalar::Uint16: {
+ uint16_t oldval = (uint16_t)oldCandidate;
+ uint16_t newval = (uint16_t)newCandidate;
+ oldval = jit::AtomicOperations::compareExchangeSeqCst(
+ viewData.cast<uint16_t*>() + offset, oldval, newval);
+ return oldval;
+ }
+ case Scalar::Int32: {
+ int32_t oldval = oldCandidate;
+ int32_t newval = newCandidate;
+ oldval = jit::AtomicOperations::compareExchangeSeqCst(
+ viewData.cast<int32_t*>() + offset, oldval, newval);
+ return oldval;
+ }
+ case Scalar::Uint32: {
+ uint32_t oldval = (uint32_t)oldCandidate;
+ uint32_t newval = (uint32_t)newCandidate;
+ oldval = jit::AtomicOperations::compareExchangeSeqCst(
+ viewData.cast<uint32_t*>() + offset, oldval, newval);
+ return (int32_t)oldval;
+ }
+ default:
+ if (badArrayType)
+ *badArrayType = true;
+ return 0;
}
}
bool
js::atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
HandleValue objv = args.get(0);
@@ -196,18 +196,18 @@ js::atomics_compareExchange(JSContext* c
int32_t oldCandidate;
if (!ToInt32(cx, oldv, &oldCandidate))
return false;
int32_t newCandidate;
if (!ToInt32(cx, newv, &newCandidate))
return false;
bool badType = false;
- int32_t result = CompareExchange(view->type(), oldCandidate, newCandidate,
- view->viewDataShared(), offset, &badType);
+ int32_t result = CompareExchange(
+ view->type(), oldCandidate, newCandidate, view->viewDataShared(), offset, &badType);
if (badType)
return ReportBadArrayType(cx);
if (view->type() == Scalar::Uint32)
r.setNumber((double)(uint32_t)result);
else
r.setInt32(result);
@@ -226,104 +226,108 @@ js::atomics_load(JSContext* cx, unsigned
if (!GetSharedTypedArray(cx, objv, &view))
return false;
uint32_t offset;
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
return false;
SharedMem<void*> viewData = view->viewDataShared();
switch (view->type()) {
- case Scalar::Uint8: {
- uint8_t v = jit::AtomicOperations::loadSeqCst(viewData.cast<uint8_t*>() + offset);
- r.setInt32(v);
- return true;
- }
- case Scalar::Int8: {
- int8_t v = jit::AtomicOperations::loadSeqCst(viewData.cast<uint8_t*>() + offset);
- r.setInt32(v);
- return true;
- }
- case Scalar::Int16: {
- int16_t v = jit::AtomicOperations::loadSeqCst(viewData.cast<int16_t*>() + offset);
- r.setInt32(v);
- return true;
- }
- case Scalar::Uint16: {
- uint16_t v = jit::AtomicOperations::loadSeqCst(viewData.cast<uint16_t*>() + offset);
- r.setInt32(v);
- return true;
- }
- case Scalar::Int32: {
- int32_t v = jit::AtomicOperations::loadSeqCst(viewData.cast<int32_t*>() + offset);
- r.setInt32(v);
- return true;
- }
- case Scalar::Uint32: {
- uint32_t v = jit::AtomicOperations::loadSeqCst(viewData.cast<uint32_t*>() + offset);
- r.setNumber(v);
- return true;
- }
- default:
- return ReportBadArrayType(cx);
+ case Scalar::Uint8: {
+ uint8_t v = jit::AtomicOperations::loadSeqCst(viewData.cast<uint8_t*>() + offset);
+ r.setInt32(v);
+ return true;
+ }
+ case Scalar::Int8: {
+ int8_t v = jit::AtomicOperations::loadSeqCst(viewData.cast<uint8_t*>() + offset);
+ r.setInt32(v);
+ return true;
+ }
+ case Scalar::Int16: {
+ int16_t v = jit::AtomicOperations::loadSeqCst(viewData.cast<int16_t*>() + offset);
+ r.setInt32(v);
+ return true;
+ }
+ case Scalar::Uint16: {
+ uint16_t v = jit::AtomicOperations::loadSeqCst(viewData.cast<uint16_t*>() + offset);
+ r.setInt32(v);
+ return true;
+ }
+ case Scalar::Int32: {
+ int32_t v = jit::AtomicOperations::loadSeqCst(viewData.cast<int32_t*>() + offset);
+ r.setInt32(v);
+ return true;
+ }
+ case Scalar::Uint32: {
+ uint32_t v = jit::AtomicOperations::loadSeqCst(viewData.cast<uint32_t*>() + offset);
+ r.setNumber(v);
+ return true;
+ }
+ default:
+ return ReportBadArrayType(cx);
}
}
-enum XchgStoreOp {
+enum XchgStoreOp
+{
DoExchange,
DoStore
};
template<XchgStoreOp op>
static int32_t
-ExchangeOrStore(Scalar::Type viewType, int32_t numberValue, SharedMem<void*> viewData,
- uint32_t offset, bool* badArrayType = nullptr)
+ExchangeOrStore(Scalar::Type viewType,
+ int32_t numberValue,
+ SharedMem<void*> viewData,
+ uint32_t offset,
+ bool* badArrayType = nullptr)
{
-#define INT_OP(ptr, value) \
- JS_BEGIN_MACRO \
- if (op == DoStore) \
- jit::AtomicOperations::storeSeqCst(ptr, value); \
- else \
- value = jit::AtomicOperations::exchangeSeqCst(ptr, value); \
+#define INT_OP(ptr, value) \
+ JS_BEGIN_MACRO \
+ if (op == DoStore) \
+ jit::AtomicOperations::storeSeqCst(ptr, value); \
+ else \
+ value = jit::AtomicOperations::exchangeSeqCst(ptr, value); \
JS_END_MACRO
switch (viewType) {
- case Scalar::Int8: {
- int8_t value = (int8_t)numberValue;
- INT_OP(viewData.cast<int8_t*>() + offset, value);
- return value;
- }
- case Scalar::Uint8: {
- uint8_t value = (uint8_t)numberValue;
- INT_OP(viewData.cast<uint8_t*>() + offset, value);
- return value;
- }
- case Scalar::Int16: {
- int16_t value = (int16_t)numberValue;
- INT_OP(viewData.cast<int16_t*>() + offset, value);
- return value;
- }
- case Scalar::Uint16: {
- uint16_t value = (uint16_t)numberValue;
- INT_OP(viewData.cast<uint16_t*>() + offset, value);
- return value;
- }
- case Scalar::Int32: {
- int32_t value = numberValue;
- INT_OP(viewData.cast<int32_t*>() + offset, value);
- return value;
- }
- case Scalar::Uint32: {
- uint32_t value = (uint32_t)numberValue;
- INT_OP(viewData.cast<uint32_t*>() + offset, value);
- return (int32_t)value;
- }
- default:
- if (badArrayType)
- *badArrayType = true;
- return 0;
+ case Scalar::Int8: {
+ int8_t value = (int8_t)numberValue;
+ INT_OP(viewData.cast<int8_t*>() + offset, value);
+ return value;
+ }
+ case Scalar::Uint8: {
+ uint8_t value = (uint8_t)numberValue;
+ INT_OP(viewData.cast<uint8_t*>() + offset, value);
+ return value;
+ }
+ case Scalar::Int16: {
+ int16_t value = (int16_t)numberValue;
+ INT_OP(viewData.cast<int16_t*>() + offset, value);
+ return value;
+ }
+ case Scalar::Uint16: {
+ uint16_t value = (uint16_t)numberValue;
+ INT_OP(viewData.cast<uint16_t*>() + offset, value);
+ return value;
+ }
+ case Scalar::Int32: {
+ int32_t value = numberValue;
+ INT_OP(viewData.cast<int32_t*>() + offset, value);
+ return value;
+ }
+ case Scalar::Uint32: {
+ uint32_t value = (uint32_t)numberValue;
+ INT_OP(viewData.cast<uint32_t*>() + offset, value);
+ return (int32_t)value;
+ }
+ default:
+ if (badArrayType)
+ *badArrayType = true;
+ return 0;
}
#undef INT_OP
}
template<XchgStoreOp op>
static bool
ExchangeOrStore(JSContext* cx, unsigned argc, Value* vp)
{
@@ -339,18 +343,18 @@ ExchangeOrStore(JSContext* cx, unsigned
uint32_t offset;
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
return false;
double integerValue;
if (!ToInteger(cx, valv, &integerValue))
return false;
bool badType = false;
- int32_t result = ExchangeOrStore<op>(view->type(), JS::ToInt32(integerValue),
- view->viewDataShared(), offset, &badType);
+ int32_t result = ExchangeOrStore<op>(
+ view->type(), JS::ToInt32(integerValue), view->viewDataShared(), offset, &badType);
if (badType)
return ReportBadArrayType(cx);
if (op == DoStore)
r.setNumber(integerValue);
else if (view->type() == Scalar::Uint32)
r.setNumber((double)(uint32_t)result);
@@ -368,133 +372,136 @@ js::atomics_store(JSContext* cx, unsigne
bool
js::atomics_exchange(JSContext* cx, unsigned argc, Value* vp)
{
return ExchangeOrStore<DoExchange>(cx, argc, vp);
}
template<typename T>
static bool
-AtomicsBinop(JSContext* cx, HandleValue objv, HandleValue idxv, HandleValue valv,
+AtomicsBinop(JSContext* cx,
+ HandleValue objv,
+ HandleValue idxv,
+ HandleValue valv,
MutableHandleValue r)
{
Rooted<TypedArrayObject*> view(cx, nullptr);
if (!GetSharedTypedArray(cx, objv, &view))
return false;
uint32_t offset;
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
return false;
int32_t numberValue;
if (!ToInt32(cx, valv, &numberValue))
return false;
SharedMem<void*> viewData = view->viewDataShared();
switch (view->type()) {
- case Scalar::Int8: {
- int8_t v = (int8_t)numberValue;
- r.setInt32(T::operate(viewData.cast<int8_t*>() + offset, v));
- return true;
- }
- case Scalar::Uint8: {
- uint8_t v = (uint8_t)numberValue;
- r.setInt32(T::operate(viewData.cast<uint8_t*>() + offset, v));
- return true;
- }
- case Scalar::Int16: {
- int16_t v = (int16_t)numberValue;
- r.setInt32(T::operate(viewData.cast<int16_t*>() + offset, v));
- return true;
- }
- case Scalar::Uint16: {
- uint16_t v = (uint16_t)numberValue;
- r.setInt32(T::operate(viewData.cast<uint16_t*>() + offset, v));
- return true;
- }
- case Scalar::Int32: {
- int32_t v = numberValue;
- r.setInt32(T::operate(viewData.cast<int32_t*>() + offset, v));
- return true;
- }
- case Scalar::Uint32: {
- uint32_t v = (uint32_t)numberValue;
- r.setNumber((double)T::operate(viewData.cast<uint32_t*>() + offset, v));
- return true;
- }
- default:
- return ReportBadArrayType(cx);
+ case Scalar::Int8: {
+ int8_t v = (int8_t)numberValue;
+ r.setInt32(T::operate(viewData.cast<int8_t*>() + offset, v));
+ return true;
+ }
+ case Scalar::Uint8: {
+ uint8_t v = (uint8_t)numberValue;
+ r.setInt32(T::operate(viewData.cast<uint8_t*>() + offset, v));
+ return true;
+ }
+ case Scalar::Int16: {
+ int16_t v = (int16_t)numberValue;
+ r.setInt32(T::operate(viewData.cast<int16_t*>() + offset, v));
+ return true;
+ }
+ case Scalar::Uint16: {
+ uint16_t v = (uint16_t)numberValue;
+ r.setInt32(T::operate(viewData.cast<uint16_t*>() + offset, v));
+ return true;
+ }
+ case Scalar::Int32: {
+ int32_t v = numberValue;
+ r.setInt32(T::operate(viewData.cast<int32_t*>() + offset, v));
+ return true;
+ }
+ case Scalar::Uint32: {
+ uint32_t v = (uint32_t)numberValue;
+ r.setNumber((double)T::operate(viewData.cast<uint32_t*>() + offset, v));
+ return true;
+ }
+ default:
+ return ReportBadArrayType(cx);
}
}
-#define INTEGRAL_TYPES_FOR_EACH(NAME) \
- static int8_t operate(SharedMem<int8_t*> addr, int8_t v) { return NAME(addr, v); } \
- static uint8_t operate(SharedMem<uint8_t*> addr, uint8_t v) { return NAME(addr, v); } \
- static int16_t operate(SharedMem<int16_t*> addr, int16_t v) { return NAME(addr, v); } \
- static uint16_t operate(SharedMem<uint16_t*> addr, uint16_t v) { return NAME(addr, v); } \
- static int32_t operate(SharedMem<int32_t*> addr, int32_t v) { return NAME(addr, v); } \
+#define INTEGRAL_TYPES_FOR_EACH(NAME) \
+ static int8_t operate(SharedMem<int8_t*> addr, int8_t v) { return NAME(addr, v); } \
+ static uint8_t operate(SharedMem<uint8_t*> addr, uint8_t v) { return NAME(addr, v); } \
+ static int16_t operate(SharedMem<int16_t*> addr, int16_t v) { return NAME(addr, v); } \
+ static uint16_t operate(SharedMem<uint16_t*> addr, uint16_t v) { return NAME(addr, v); } \
+ static int32_t operate(SharedMem<int32_t*> addr, int32_t v) { return NAME(addr, v); } \
static uint32_t operate(SharedMem<uint32_t*> addr, uint32_t v) { return NAME(addr, v); }
class PerformAdd
{
-public:
+ public:
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchAddSeqCst)
static int32_t perform(int32_t x, int32_t y) { return x + y; }
};
bool
js::atomics_add(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return AtomicsBinop<PerformAdd>(cx, args.get(0), args.get(1), args.get(2), args.rval());
}
class PerformSub
{
-public:
+ public:
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchSubSeqCst)
static int32_t perform(int32_t x, int32_t y) { return x - y; }
};
bool
js::atomics_sub(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return AtomicsBinop<PerformSub>(cx, args.get(0), args.get(1), args.get(2), args.rval());
}
class PerformAnd
{
-public:
+ public:
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchAndSeqCst)
static int32_t perform(int32_t x, int32_t y) { return x & y; }
};
bool
js::atomics_and(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return AtomicsBinop<PerformAnd>(cx, args.get(0), args.get(1), args.get(2), args.rval());
}
class PerformOr
{
-public:
+ public:
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchOrSeqCst)
static int32_t perform(int32_t x, int32_t y) { return x | y; }
};
bool
js::atomics_or(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return AtomicsBinop<PerformOr>(cx, args.get(0), args.get(1), args.get(2), args.rval());
}
class PerformXor
{
-public:
+ public:
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchXorSeqCst)
static int32_t perform(int32_t x, int32_t y) { return x ^ y; }
};
bool
js::atomics_xor(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
@@ -537,164 +544,168 @@ js::atomics_add_asm_callout(wasm::Instan
{
SharedMem<void*> heap = instance->memoryBase().cast<void*>();
size_t heapLength = instance->memoryLength();
if (size_t(offset) >= heapLength)
return 0;
switch (Scalar::Type(vt)) {
- case Scalar::Int8:
- return PerformAdd::operate(heap.cast<int8_t*>() + offset, value);
- case Scalar::Uint8:
- return PerformAdd::operate(heap.cast<uint8_t*>() + offset, value);
- case Scalar::Int16:
- return PerformAdd::operate(heap.cast<int16_t*>() + (offset >> 1), value);
- case Scalar::Uint16:
- return PerformAdd::operate(heap.cast<uint16_t*>() + (offset >> 1), value);
- default:
- MOZ_CRASH("Invalid size");
+ case Scalar::Int8:
+ return PerformAdd::operate(heap.cast<int8_t*>() + offset, value);
+ case Scalar::Uint8:
+ return PerformAdd::operate(heap.cast<uint8_t*>() + offset, value);
+ case Scalar::Int16:
+ return PerformAdd::operate(heap.cast<int16_t*>() + (offset >> 1), value);
+ case Scalar::Uint16:
+ return PerformAdd::operate(heap.cast<uint16_t*>() + (offset >> 1), value);
+ default:
+ MOZ_CRASH("Invalid size");
}
}
int32_t
js::atomics_sub_asm_callout(wasm::Instance* instance, int32_t vt, int32_t offset, int32_t value)
{
SharedMem<void*> heap = instance->memoryBase().cast<void*>();
size_t heapLength = instance->memoryLength();
if (size_t(offset) >= heapLength)
return 0;
switch (Scalar::Type(vt)) {
- case Scalar::Int8:
- return PerformSub::operate(heap.cast<int8_t*>() + offset, value);
- case Scalar::Uint8:
- return PerformSub::operate(heap.cast<uint8_t*>() + offset, value);
- case Scalar::Int16:
- return PerformSub::operate(heap.cast<int16_t*>() + (offset >> 1), value);
- case Scalar::Uint16:
- return PerformSub::operate(heap.cast<uint16_t*>() + (offset >> 1), value);
- default:
- MOZ_CRASH("Invalid size");
+ case Scalar::Int8:
+ return PerformSub::operate(heap.cast<int8_t*>() + offset, value);
+ case Scalar::Uint8:
+ return PerformSub::operate(heap.cast<uint8_t*>() + offset, value);
+ case Scalar::Int16:
+ return PerformSub::operate(heap.cast<int16_t*>() + (offset >> 1), value);
+ case Scalar::Uint16:
+ return PerformSub::operate(heap.cast<uint16_t*>() + (offset >> 1), value);
+ default:
+ MOZ_CRASH("Invalid size");
}
}
int32_t
js::atomics_and_asm_callout(wasm::Instance* instance, int32_t vt, int32_t offset, int32_t value)
{
SharedMem<void*> heap = instance->memoryBase().cast<void*>();
size_t heapLength = instance->memoryLength();
if (size_t(offset) >= heapLength)
return 0;
switch (Scalar::Type(vt)) {
- case Scalar::Int8:
- return PerformAnd::operate(heap.cast<int8_t*>() + offset, value);
- case Scalar::Uint8:
- return PerformAnd::operate(heap.cast<uint8_t*>() + offset, value);
- case Scalar::Int16:
- return PerformAnd::operate(heap.cast<int16_t*>() + (offset >> 1), value);
- case Scalar::Uint16:
- return PerformAnd::operate(heap.cast<uint16_t*>() + (offset >> 1), value);
- default:
- MOZ_CRASH("Invalid size");
+ case Scalar::Int8:
+ return PerformAnd::operate(heap.cast<int8_t*>() + offset, value);
+ case Scalar::Uint8:
+ return PerformAnd::operate(heap.cast<uint8_t*>() + offset, value);
+ case Scalar::Int16:
+ return PerformAnd::operate(heap.cast<int16_t*>() + (offset >> 1), value);
+ case Scalar::Uint16:
+ return PerformAnd::operate(heap.cast<uint16_t*>() + (offset >> 1), value);
+ default:
+ MOZ_CRASH("Invalid size");
}
}
int32_t
js::atomics_or_asm_callout(wasm::Instance* instance, int32_t vt, int32_t offset, int32_t value)
{
SharedMem<void*> heap = instance->memoryBase().cast<void*>();
size_t heapLength = instance->memoryLength();
if (size_t(offset) >= heapLength)
return 0;
switch (Scalar::Type(vt)) {
- case Scalar::Int8:
- return PerformOr::operate(heap.cast<int8_t*>() + offset, value);
- case Scalar::Uint8:
- return PerformOr::operate(heap.cast<uint8_t*>() + offset, value);
- case Scalar::Int16:
- return PerformOr::operate(heap.cast<int16_t*>() + (offset >> 1), value);
- case Scalar::Uint16:
- return PerformOr::operate(heap.cast<uint16_t*>() + (offset >> 1), value);
- default:
- MOZ_CRASH("Invalid size");
+ case Scalar::Int8:
+ return PerformOr::operate(heap.cast<int8_t*>() + offset, value);
+ case Scalar::Uint8:
+ return PerformOr::operate(heap.cast<uint8_t*>() + offset, value);
+ case Scalar::Int16:
+ return PerformOr::operate(heap.cast<int16_t*>() + (offset >> 1), value);
+ case Scalar::Uint16:
+ return PerformOr::operate(heap.cast<uint16_t*>() + (offset >> 1), value);
+ default:
+ MOZ_CRASH("Invalid size");
}
}
int32_t
js::atomics_xor_asm_callout(wasm::Instance* instance, int32_t vt, int32_t offset, int32_t value)
{
SharedMem<void*> heap = instance->memoryBase().cast<void*>();
size_t heapLength = instance->memoryLength();
if (size_t(offset) >= heapLength)
return 0;
switch (Scalar::Type(vt)) {
- case Scalar::Int8:
- return PerformXor::operate(heap.cast<int8_t*>() + offset, value);
- case Scalar::Uint8:
- return PerformXor::operate(heap.cast<uint8_t*>() + offset, value);
- case Scalar::Int16:
- return PerformXor::operate(heap.cast<int16_t*>() + (offset >> 1), value);
- case Scalar::Uint16:
- return PerformXor::operate(heap.cast<uint16_t*>() + (offset >> 1), value);
- default:
- MOZ_CRASH("Invalid size");
+ case Scalar::Int8:
+ return PerformXor::operate(heap.cast<int8_t*>() + offset, value);
+ case Scalar::Uint8:
+ return PerformXor::operate(heap.cast<uint8_t*>() + offset, value);
+ case Scalar::Int16:
+ return PerformXor::operate(heap.cast<int16_t*>() + (offset >> 1), value);
+ case Scalar::Uint16:
+ return PerformXor::operate(heap.cast<uint16_t*>() + (offset >> 1), value);
+ default:
+ MOZ_CRASH("Invalid size");
}
}
int32_t
js::atomics_xchg_asm_callout(wasm::Instance* instance, int32_t vt, int32_t offset, int32_t value)
{
SharedMem<void*> heap = instance->memoryBase().cast<void*>();
size_t heapLength = instance->memoryLength();
if (size_t(offset) >= heapLength)
return 0;
switch (Scalar::Type(vt)) {
- case Scalar::Int8:
- return ExchangeOrStore<DoExchange>(Scalar::Int8, value, heap, offset);
- case Scalar::Uint8:
- return ExchangeOrStore<DoExchange>(Scalar::Uint8, value, heap, offset);
- case Scalar::Int16:
- return ExchangeOrStore<DoExchange>(Scalar::Int16, value, heap, offset>>1);
- case Scalar::Uint16:
- return ExchangeOrStore<DoExchange>(Scalar::Uint16, value, heap, offset>>1);
- default:
- MOZ_CRASH("Invalid size");
+ case Scalar::Int8:
+ return ExchangeOrStore<DoExchange>(Scalar::Int8, value, heap, offset);
+ case Scalar::Uint8:
+ return ExchangeOrStore<DoExchange>(Scalar::Uint8, value, heap, offset);
+ case Scalar::Int16:
+ return ExchangeOrStore<DoExchange>(Scalar::Int16, value, heap, offset >> 1);
+ case Scalar::Uint16:
+ return ExchangeOrStore<DoExchange>(Scalar::Uint16, value, heap, offset >> 1);
+ default:
+ MOZ_CRASH("Invalid size");
}
}
int32_t
-js::atomics_cmpxchg_asm_callout(wasm::Instance* instance, int32_t vt, int32_t offset, int32_t oldval, int32_t newval)
+js::atomics_cmpxchg_asm_callout(wasm::Instance* instance,
+ int32_t vt,
+ int32_t offset,
+ int32_t oldval,
+ int32_t newval)
{
SharedMem<void*> heap = instance->memoryBase().cast<void*>();
size_t heapLength = instance->memoryLength();
if (size_t(offset) >= heapLength)
return 0;
switch (Scalar::Type(vt)) {
- case Scalar::Int8:
- return CompareExchange(Scalar::Int8, oldval, newval, heap, offset);
- case Scalar::Uint8:
- return CompareExchange(Scalar::Uint8, oldval, newval, heap, offset);
- case Scalar::Int16:
- return CompareExchange(Scalar::Int16, oldval, newval, heap, offset>>1);
- case Scalar::Uint16:
- return CompareExchange(Scalar::Uint16, oldval, newval, heap, offset>>1);
- default:
- MOZ_CRASH("Invalid size");
+ case Scalar::Int8:
+ return CompareExchange(Scalar::Int8, oldval, newval, heap, offset);
+ case Scalar::Uint8:
+ return CompareExchange(Scalar::Uint8, oldval, newval, heap, offset);
+ case Scalar::Int16:
+ return CompareExchange(Scalar::Int16, oldval, newval, heap, offset >> 1);
+ case Scalar::Uint16:
+ return CompareExchange(Scalar::Uint16, oldval, newval, heap, offset >> 1);
+ default:
+ MOZ_CRASH("Invalid size");
}
}
namespace js {
// Represents one waiting worker.
//
// The type is declared opaque in SharedArrayObject.h. Instances of
@@ -707,44 +718,43 @@ namespace js {
// The list is circular, so the 'lower_pri' field of the lowest priority
// node points to the first node in the list. The list has no dedicated
// header node.
class FutexWaiter
{
public:
FutexWaiter(uint32_t offset, JSContext* cx)
- : offset(offset),
- cx(cx),
- lower_pri(nullptr),
- back(nullptr)
+ : offset(offset)
+ , cx(cx)
+ , lower_pri(nullptr)
+ , back(nullptr)
{
}
- uint32_t offset; // int32 element index within the SharedArrayBuffer
- JSContext* cx; // The waiting thread
- FutexWaiter* lower_pri; // Lower priority nodes in circular doubly-linked list of waiters
- FutexWaiter* back; // Other direction
+ uint32_t offset; // int32 element index within the SharedArrayBuffer
+ JSContext* cx; // The waiting thread
+ FutexWaiter* lower_pri; // Lower priority nodes in circular doubly-linked list of waiters
+ FutexWaiter* back; // Other direction
};
class AutoLockFutexAPI
{
// We have to wrap this in a Maybe because of the way loading
// mozilla::Atomic pointers works.
mozilla::Maybe<js::UniqueLock<js::Mutex>> unique_;
public:
- AutoLockFutexAPI() {
+ AutoLockFutexAPI()
+ {
js::Mutex* lock = FutexThread::lock_;
unique_.emplace(*lock);
}
- ~AutoLockFutexAPI() {
- unique_.reset();
- }
+ ~AutoLockFutexAPI() { unique_.reset(); }
js::UniqueLock<js::Mutex>& unique() { return *unique_; }
};
} // namespace js
bool
js::atomics_wait(JSContext* cx, unsigned argc, Value* vp)
@@ -806,22 +816,22 @@ js::atomics_wait(JSContext* cx, unsigned
w.lower_pri = w.back = &w;
sarb->setWaiters(&w);
}
FutexThread::WaitResult result = FutexThread::FutexOK;
bool retval = cx->fx.wait(cx, lock.unique(), timeout, &result);
if (retval) {
switch (result) {
- case FutexThread::FutexOK:
- r.setString(cx->names().futexOK);
- break;
- case FutexThread::FutexTimedOut:
- r.setString(cx->names().futexTimedOut);
- break;
+ case FutexThread::FutexOK:
+ r.setString(cx->names().futexOK);
+ break;
+ case FutexThread::FutexTimedOut:
+ r.setString(cx->names().futexTimedOut);
+ break;
}
}
if (w.lower_pri == &w) {
sarb->setWaiters(nullptr);
} else {
w.lower_pri->back = w.back;
w.back->lower_pri = w.lower_pri;
@@ -916,19 +926,19 @@ js::FutexThread::unlock()
{
// Load the atomic pointer.
js::Mutex* lock = lock_;
lock->unlock();
}
js::FutexThread::FutexThread()
- : cond_(nullptr),
- state_(Idle),
- canWait_(false)
+ : cond_(nullptr)
+ , state_(Idle)
+ , canWait_(false)
{
}
bool
js::FutexThread::initInstance()
{
MOZ_ASSERT(lock_);
cond_ = js_new<js::ConditionVariable>();
@@ -946,47 +956,46 @@ bool
js::FutexThread::isWaiting()
{
// When a worker is awoken for an interrupt it goes into state
// WaitingNotifiedForInterrupt for a short time before it actually
// wakes up and goes into WaitingInterrupted. In those states the
// worker is still waiting, and if an explicit wake arrives the
// worker transitions to Woken. See further comments in
// FutexThread::wait().
- return state_ == Waiting || state_ == WaitingInterrupted || state_ == WaitingNotifiedForInterrupt;
+ return state_ == Waiting || state_ == WaitingInterrupted ||
+ state_ == WaitingNotifiedForInterrupt;
}
bool
-js::FutexThread::wait(JSContext* cx, js::UniqueLock<js::Mutex>& locked,
- mozilla::Maybe<mozilla::TimeDuration>& timeout, WaitResult* result)
+js::FutexThread::wait(JSContext* cx,
+ js::UniqueLock<js::Mutex>& locked,
+ mozilla::Maybe<mozilla::TimeDuration>& timeout,
+ WaitResult* result)
{
MOZ_ASSERT(&cx->fx == this);
MOZ_ASSERT(cx->fx.canWait());
MOZ_ASSERT(state_ == Idle || state_ == WaitingInterrupted);
// Disallow waiting when a runtime is processing an interrupt.
// See explanation below.
if (state_ == WaitingInterrupted) {
UnlockGuard<Mutex> unlock(locked);
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ATOMICS_WAIT_NOT_ALLOWED);
return false;
}
// Go back to Idle after returning.
- auto onFinish = mozilla::MakeScopeExit([&] {
- state_ = Idle;
- });
+ auto onFinish = mozilla::MakeScopeExit([&] { state_ = Idle; });
const bool isTimed = timeout.isSome();
- auto finalEnd = timeout.map([](mozilla::TimeDuration& timeout) {
- return mozilla::TimeStamp::Now() + timeout;
- });
-
+ auto finalEnd = timeout.map(
+ [](mozilla::TimeDuration& timeout) { return mozilla::TimeStamp::Now() + timeout; });
// 4000s is about the longest timeout slice that is guaranteed to
// work cross-platform.
auto maxSlice = mozilla::TimeDuration::FromSeconds(4000.0);
for (;;) {
// If we are doing a timed wait, calculate the end time for this wait
// slice.
@@ -1001,142 +1010,142 @@ js::FutexThread::wait(JSContext* cx, js:
if (isTimed) {
mozilla::Unused << cond_->wait_until(locked, *sliceEnd);
} else {
cond_->wait(locked);
}
switch (state_) {
- case FutexThread::Waiting:
- // Timeout or spurious wakeup.
- if (isTimed) {
- auto now = mozilla::TimeStamp::Now();
- if (now >= *finalEnd) {
- *result = FutexTimedOut;
+ case FutexThread::Waiting:
+ // Timeout or spurious wakeup.
+ if (isTimed) {
+ auto now = mozilla::TimeStamp::Now();
+ if (now >= *finalEnd) {
+ *result = FutexTimedOut;
+ return true;
+ }
+ }
+ break;
+
+ case FutexThread::Woken:
+ *result = FutexOK;
+ return true;
+
+ case FutexThread::WaitingNotifiedForInterrupt:
+ // The interrupt handler may reenter the engine. In that case
+ // there are two complications:
+ //
+ // - The waiting thread is not actually waiting on the
+ // condition variable so we have to record that it
+ // should be woken when the interrupt handler returns.
+ // To that end, we flag the thread as interrupted around
+ // the interrupt and check state_ when the interrupt
+ // handler returns. A wake() call that reaches the
+ // runtime during the interrupt sets state_ to Woken.
+ //
+ // - It is in principle possible for wait() to be
+ // reentered on the same thread/runtime and waiting on the
+ // same location and to yet again be interrupted and enter
+ // the interrupt handler. In this case, it is important
+ // that when another agent wakes waiters, all waiters using
+ // the same runtime on the same location are woken in LIFO
+ // order; FIFO may be the required order, but FIFO would
+ // fail to wake up the innermost call. Interrupts are
+ // outside any spec anyway. Also, several such suspended
+ // waiters may be woken at a time.
+ //
+ // For the time being we disallow waiting from within code
+ // that runs from within an interrupt handler; this may
+ // occasionally (very rarely) be surprising but is
+ // expedient. Other solutions exist, see bug #1131943. The
+ // code that performs the check is above, at the head of
+ // this function.
+
+ state_ = WaitingInterrupted;
+ {
+ UnlockGuard<Mutex> unlock(locked);
+ if (!cx->handleInterrupt())
+ return false;
+ }
+ if (state_ == Woken) {
+ *result = FutexOK;
return true;
}
- }
- break;
-
- case FutexThread::Woken:
- *result = FutexOK;
- return true;
+ break;
- case FutexThread::WaitingNotifiedForInterrupt:
- // The interrupt handler may reenter the engine. In that case
- // there are two complications:
- //
- // - The waiting thread is not actually waiting on the
- // condition variable so we have to record that it
- // should be woken when the interrupt handler returns.
- // To that end, we flag the thread as interrupted around
- // the interrupt and check state_ when the interrupt
- // handler returns. A wake() call that reaches the
- // runtime during the interrupt sets state_ to Woken.
- //
- // - It is in principle possible for wait() to be
- // reentered on the same thread/runtime and waiting on the
- // same location and to yet again be interrupted and enter
- // the interrupt handler. In this case, it is important
- // that when another agent wakes waiters, all waiters using
- // the same runtime on the same location are woken in LIFO
- // order; FIFO may be the required order, but FIFO would
- // fail to wake up the innermost call. Interrupts are
- // outside any spec anyway. Also, several such suspended
- // waiters may be woken at a time.
- //
- // For the time being we disallow waiting from within code
- // that runs from within an interrupt handler; this may
- // occasionally (very rarely) be surprising but is
- // expedient. Other solutions exist, see bug #1131943. The
- // code that performs the check is above, at the head of
- // this function.
-
- state_ = WaitingInterrupted;
- {
- UnlockGuard<Mutex> unlock(locked);
- if (!cx->handleInterrupt())
- return false;
- }
- if (state_ == Woken) {
- *result = FutexOK;
- return true;
- }
- break;
-
- default:
- MOZ_CRASH("Bad FutexState in wait()");
+ default:
+ MOZ_CRASH("Bad FutexState in wait()");
}
}
}
void
js::FutexThread::wake(WakeReason reason)
{
MOZ_ASSERT(isWaiting());
- if ((state_ == WaitingInterrupted || state_ == WaitingNotifiedForInterrupt) && reason == WakeExplicit) {
+ if ((state_ == WaitingInterrupted || state_ == WaitingNotifiedForInterrupt) &&
+ reason == WakeExplicit) {
state_ = Woken;
return;
}
switch (reason) {
- case WakeExplicit:
- state_ = Woken;
- break;
- case WakeForJSInterrupt:
- if (state_ == WaitingNotifiedForInterrupt)
- return;
- state_ = WaitingNotifiedForInterrupt;
- break;
- default:
- MOZ_CRASH("bad WakeReason in FutexThread::wake()");
+ case WakeExplicit:
+ state_ = Woken;
+ break;
+ case WakeForJSInterrupt:
+ if (state_ == WaitingNotifiedForInterrupt)
+ return;
+ state_ = WaitingNotifiedForInterrupt;
+ break;
+ default:
+ MOZ_CRASH("bad WakeReason in FutexThread::wake()");
}
cond_->notify_all();
}
const JSFunctionSpec AtomicsMethods[] = {
- JS_INLINABLE_FN("compareExchange", atomics_compareExchange, 4,0, AtomicsCompareExchange),
- JS_INLINABLE_FN("load", atomics_load, 2,0, AtomicsLoad),
- JS_INLINABLE_FN("store", atomics_store, 3,0, AtomicsStore),
- JS_INLINABLE_FN("exchange", atomics_exchange, 3,0, AtomicsExchange),
- JS_INLINABLE_FN("add", atomics_add, 3,0, AtomicsAdd),
- JS_INLINABLE_FN("sub", atomics_sub, 3,0, AtomicsSub),
- JS_INLINABLE_FN("and", atomics_and, 3,0, AtomicsAnd),
- JS_INLINABLE_FN("or", atomics_or, 3,0, AtomicsOr),
- JS_INLINABLE_FN("xor", atomics_xor, 3,0, AtomicsXor),
- JS_INLINABLE_FN("isLockFree", atomics_isLockFree, 1,0, AtomicsIsLockFree),
- JS_FN("wait", atomics_wait, 4,0),
- JS_FN("wake", atomics_wake, 3,0),
+ JS_INLINABLE_FN("compareExchange", atomics_compareExchange, 4, 0, AtomicsCompareExchange),
+ JS_INLINABLE_FN("load", atomics_load, 2, 0, AtomicsLoad),
+ JS_INLINABLE_FN("store", atomics_store, 3, 0, AtomicsStore),
+ JS_INLINABLE_FN("exchange", atomics_exchange, 3, 0, AtomicsExchange),
+ JS_INLINABLE_FN("add", atomics_add, 3, 0, AtomicsAdd),
+ JS_INLINABLE_FN("sub", atomics_sub, 3, 0, AtomicsSub),
+ JS_INLINABLE_FN("and", atomics_and, 3, 0, AtomicsAnd),
+ JS_INLINABLE_FN("or", atomics_or, 3, 0, AtomicsOr),
+ JS_INLINABLE_FN("xor", atomics_xor, 3, 0, AtomicsXor),
+ JS_INLINABLE_FN("isLockFree", atomics_isLockFree, 1, 0, AtomicsIsLockFree),
+ JS_FN("wait", atomics_wait, 4, 0),
+ JS_FN("wake", atomics_wake, 3, 0),
JS_FS_END
};
JSObject*
AtomicsObject::initClass(JSContext* cx, Handle<GlobalObject*> global)
{
// Create Atomics Object.
RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
if (!objProto)
return nullptr;
- RootedObject Atomics(cx, NewObjectWithGivenProto(cx, &AtomicsObject::class_, objProto,
- SingletonObject));
+ RootedObject Atomics(
+ cx, NewObjectWithGivenProto(cx, &AtomicsObject::class_, objProto, SingletonObject));
if (!Atomics)
return nullptr;
if (!JS_DefineFunctions(cx, Atomics, AtomicsMethods))
return nullptr;
if (!DefineToStringTag(cx, Atomics, cx->names().Atomics))
return nullptr;
RootedValue AtomicsValue(cx, ObjectValue(*Atomics));
// Everything is set up, install Atomics on the global object.
- if (!DefineProperty(cx, global, cx->names().Atomics, AtomicsValue, nullptr, nullptr,
- JSPROP_RESOLVING))
- {
+ if (!DefineProperty(
+ cx, global, cx->names().Atomics, AtomicsValue, nullptr, nullptr, JSPROP_RESOLVING)) {
return nullptr;
}
global->setConstructor(JSProto_Atomics, AtomicsValue);
return Atomics;
}
JSObject*
--- a/js/src/builtin/AtomicsObject.h
+++ b/js/src/builtin/AtomicsObject.h
@@ -20,79 +20,108 @@ namespace js {
class AtomicsObject : public JSObject
{
public:
static const Class class_;
static JSObject* initClass(JSContext* cx, Handle<GlobalObject*> global);
static MOZ_MUST_USE bool toString(JSContext* cx, unsigned int argc, Value* vp);
};
-MOZ_MUST_USE bool atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp);
-MOZ_MUST_USE bool atomics_exchange(JSContext* cx, unsigned argc, Value* vp);
-MOZ_MUST_USE bool atomics_load(JSContext* cx, unsigned argc, Value* vp);
-MOZ_MUST_USE bool atomics_store(JSContext* cx, unsigned argc, Value* vp);
-MOZ_MUST_USE bool atomics_add(JSContext* cx, unsigned argc, Value* vp);
-MOZ_MUST_USE bool atomics_sub(JSContext* cx, unsigned argc, Value* vp);
-MOZ_MUST_USE bool atomics_and(JSContext* cx, unsigned argc, Value* vp);
-MOZ_MUST_USE bool atomics_or(JSContext* cx, unsigned argc, Value* vp);
-MOZ_MUST_USE bool atomics_xor(JSContext* cx, unsigned argc, Value* vp);
-MOZ_MUST_USE bool atomics_isLockFree(JSContext* cx, unsigned argc, Value* vp);
-MOZ_MUST_USE bool atomics_wait(JSContext* cx, unsigned argc, Value* vp);
-MOZ_MUST_USE bool atomics_wake(JSContext* cx, unsigned argc, Value* vp);
+MOZ_MUST_USE bool
+atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp);
+MOZ_MUST_USE bool
+atomics_exchange(JSContext* cx, unsigned argc, Value* vp);
+MOZ_MUST_USE bool
+atomics_load(JSContext* cx, unsigned argc, Value* vp);
+MOZ_MUST_USE bool
+atomics_store(JSContext* cx, unsigned argc, Value* vp);
+MOZ_MUST_USE bool
+atomics_add(JSContext* cx, unsigned argc, Value* vp);
+MOZ_MUST_USE bool
+atomics_sub(JSContext* cx, unsigned argc, Value* vp);
+MOZ_MUST_USE bool
+atomics_and(JSContext* cx, unsigned argc, Value* vp);
+MOZ_MUST_USE bool
+atomics_or(JSContext* cx, unsigned argc, Value* vp);
+MOZ_MUST_USE bool
+atomics_xor(JSContext* cx, unsigned argc, Value* vp);
+MOZ_MUST_USE bool
+atomics_isLockFree(JSContext* cx, unsigned argc, Value* vp);
+MOZ_MUST_USE bool
+atomics_wait(JSContext* cx, unsigned argc, Value* vp);
+MOZ_MUST_USE bool
+atomics_wake(JSContext* cx, unsigned argc, Value* vp);
/* asm.js callouts */
-namespace wasm { class Instance; }
-int32_t atomics_add_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
-int32_t atomics_sub_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
-int32_t atomics_and_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
-int32_t atomics_or_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
-int32_t atomics_xor_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
-int32_t atomics_cmpxchg_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t oldval, int32_t newval);
-int32_t atomics_xchg_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
+namespace wasm {
+class Instance;
+}
+int32_t
+atomics_add_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
+int32_t
+atomics_sub_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
+int32_t
+atomics_and_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
+int32_t
+atomics_or_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
+int32_t
+atomics_xor_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
+int32_t
+atomics_cmpxchg_asm_callout(wasm::Instance* i,
+ int32_t vt,
+ int32_t offset,
+ int32_t oldval,
+ int32_t newval);
+int32_t
+atomics_xchg_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
class FutexThread
{
friend class AutoLockFutexAPI;
-public:
+ public:
static MOZ_MUST_USE bool initialize();
static void destroy();
static void lock();
static void unlock();
FutexThread();
MOZ_MUST_USE bool initInstance();
void destroyInstance();
// Parameters to wake().
- enum WakeReason {
- WakeExplicit, // Being asked to wake up by another thread
- WakeForJSInterrupt // Interrupt requested
+ enum WakeReason
+ {
+ WakeExplicit, // Being asked to wake up by another thread
+ WakeForJSInterrupt // Interrupt requested
};
// Result code from wait().
- enum WaitResult {
+ enum WaitResult
+ {
FutexOK,
FutexTimedOut
};
// Block the calling thread and wait.
//
// The futex lock must be held around this call.
//
// The timeout is the number of milliseconds, with fractional
// times allowed; specify mozilla::Nothing() for an indefinite
// wait.
//
// wait() will not wake up spuriously. It will return true and
// set *result to a return code appropriate for
// Atomics.wait() on success, and return false on error.
- MOZ_MUST_USE bool wait(JSContext* cx, js::UniqueLock<js::Mutex>& locked,
- mozilla::Maybe<mozilla::TimeDuration>& timeout, WaitResult* result);
+ MOZ_MUST_USE bool wait(JSContext* cx,
+ js::UniqueLock<js::Mutex>& locked,
+ mozilla::Maybe<mozilla::TimeDuration>& timeout,
+ WaitResult* result);
// Wake the thread this is associated with.
//
// The futex lock must be held around this call. (The sleeping
// thread will not wake up until the caller of Atomics.wake()
// releases the lock.)
//
// If the thread is not waiting then this method does nothing.
@@ -106,26 +135,23 @@ public:
// with WaitingNotifiedForInterrupt; in the latter case the caller
// of wait() must handle the interrupt.
void wake(WakeReason reason);
bool isWaiting();
// If canWait() returns false (the default) then wait() is disabled
// on the thread to which the FutexThread belongs.
- bool canWait() {
- return canWait_;
- }
+ bool canWait() { return canWait_; }
- void setCanWait(bool flag) {
- canWait_ = flag;
- }
+ void setCanWait(bool flag) { canWait_ = flag; }
private:
- enum FutexState {
+ enum FutexState
+ {
Idle, // We are not waiting or woken
Waiting, // We are waiting, nothing has happened yet
WaitingNotifiedForInterrupt, // We are waiting, but have been interrupted,
// and have not yet started running the
// interrupt handler
WaitingInterrupted, // We are waiting, but have been interrupted
// and are running the interrupt handler
Woken // Woken by a script call to Atomics.wake
@@ -146,11 +172,11 @@ public:
// A flag that controls whether waiting is allowed.
ThreadLocalData<bool> canWait_;
};
JSObject*
InitAtomicsClass(JSContext* cx, HandleObject obj);
-} /* namespace js */
+} /* namespace js */
#endif /* builtin_AtomicsObject_h */
--- a/js/src/builtin/DataViewObject.cpp
+++ b/js/src/builtin/DataViewObject.cpp
@@ -12,17 +12,17 @@
#include <string.h>
#include "jsapi.h"
#include "jsarray.h"
#include "jscntxt.h"
#include "jsnum.h"
#include "jsobj.h"
#ifdef XP_WIN
-# include "jswin.h"
+#include "jswin.h"
#endif
#include "jswrapper.h"
#include "jit/AtomicOperations.h"
#include "js/Conversions.h"
#include "vm/ArrayBufferObject.h"
#include "vm/GlobalObject.h"
#include "vm/Interpreter.h"
@@ -50,18 +50,21 @@ DataViewNewObjectKind(JSContext* cx, uin
jsbytecode* pc;
JSScript* script = cx->currentScript(&pc);
if (script && ObjectGroup::useSingletonForAllocationSite(script, pc, &DataViewObject::class_))
return SingletonObject;
return GenericObject;
}
DataViewObject*
-DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
- Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, JSObject* protoArg)
+DataViewObject::create(JSContext* cx,
+ uint32_t byteOffset,
+ uint32_t byteLength,
+ Handle<ArrayBufferObjectMaybeShared*> arrayBuffer,
+ JSObject* protoArg)
{
if (arrayBuffer->isDetached()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
return nullptr;
}
MOZ_ASSERT(byteOffset <= INT32_MAX);
MOZ_ASSERT(byteLength <= INT32_MAX);
@@ -76,19 +79,18 @@ DataViewObject::create(JSContext* cx, ui
return nullptr;
if (!proto) {
if (byteLength >= TypedArrayObject::SINGLETON_BYTE_LENGTH) {
MOZ_ASSERT(obj->isSingleton());
} else {
jsbytecode* pc;
RootedScript script(cx, cx->currentScript(&pc));
- if (script && !ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, obj,
- newKind == SingletonObject))
- {
+ if (script && !ObjectGroup::setAllocationSiteObjectGroup(
+ cx, script, pc, obj, newKind == SingletonObject)) {
return nullptr;
}
}
}
// Caller should have established these preconditions, and no
// (non-self-hosted) JS code has had an opportunity to run so nothing can
// have invalidated them.
@@ -139,23 +141,31 @@ DataViewObject::create(JSContext* cx, ui
}
return &dvobj;
}
// ES2017 draft rev 931261ecef9b047b14daacf82884134da48dfe0f
// 24.3.2.1 DataView (extracted part of the main algorithm)
bool
-DataViewObject::getAndCheckConstructorArgs(JSContext* cx, HandleObject bufobj, const CallArgs& args,
- uint32_t* byteOffsetPtr, uint32_t* byteLengthPtr)
+DataViewObject::getAndCheckConstructorArgs(JSContext* cx,
+ HandleObject bufobj,
+ const CallArgs& args,
+ uint32_t* byteOffsetPtr,
+ uint32_t* byteLengthPtr)
{
// Step 3.
if (!IsArrayBufferMaybeShared(bufobj)) {
- JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
- "DataView", "ArrayBuffer", bufobj->getClass()->name);
+ JS_ReportErrorNumberASCII(cx,
+ GetErrorMessage,
+ nullptr,
+ JSMSG_NOT_EXPECTED_TYPE,
+ "DataView",
+ "ArrayBuffer",
+ bufobj->getClass()->name);
return false;
}
Rooted<ArrayBufferObjectMaybeShared*> buffer(cx, &AsArrayBufferMaybeShared(bufobj));
// Step 4.
uint64_t offset;
if (!ToIndex(cx, args.get(1), &offset))
return false;
@@ -178,24 +188,23 @@ DataViewObject::getAndCheckConstructorAr
// Step 8.a
uint64_t viewByteLength = bufferByteLength - offset;
if (args.hasDefined(2)) {
// Step 9.a.
if (!ToIndex(cx, args.get(2), &viewByteLength))
return false;
-
MOZ_ASSERT(offset + viewByteLength >= offset,
"can't overflow: both numbers are less than DOUBLE_INTEGRAL_PRECISION_LIMIT");
// Step 9.b.
if (offset + viewByteLength > bufferByteLength) {
- JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
- JSMSG_ARG_INDEX_OUT_OF_RANGE, "2");
+ JS_ReportErrorNumberASCII(
+ cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "2");
return false;
}
}
MOZ_ASSERT(viewByteLength <= INT32_MAX);
*byteOffsetPtr = AssertedCast<uint32_t>(offset);
*byteLengthPtr = AssertedCast<uint32_t>(viewByteLength);
return true;
@@ -309,25 +318,26 @@ DataViewObject::construct(JSContext* cx,
if (!GetFirstArgumentAsObject(cx, args, "DataView constructor", &bufobj))
return false;
if (bufobj->is<WrapperObject>())
return constructWrapped(cx, bufobj, args);
return constructSameCompartment(cx, bufobj, args);
}
-template <typename NativeType>
+template<typename NativeType>
/* static */ SharedMem<uint8_t*>
-DataViewObject::getDataPointer(JSContext* cx, Handle<DataViewObject*> obj, uint64_t offset,
+DataViewObject::getDataPointer(JSContext* cx,
+ Handle<DataViewObject*> obj,
+ uint64_t offset,
bool* isSharedMemory)
{
const size_t TypeSize = sizeof(NativeType);
if (offset > UINT32_MAX - TypeSize || offset + TypeSize > obj->byteLength()) {
- JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
- "1");
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
return SharedMem<uint8_t*>::unshared(nullptr);
}
MOZ_ASSERT(offset < UINT32_MAX);
*isSharedMemory = obj->isSharedMemory();
return obj->dataPointerEither().cast<uint8_t*>() + uint32_t(offset);
}
@@ -351,39 +361,73 @@ static inline uint16_t
swapBytes(uint16_t x)
{
return ((x & 0xff) << 8) | (x >> 8);
}
static inline uint32_t
swapBytes(uint32_t x)
{
- return ((x & 0xff) << 24) |
- ((x & 0xff00) << 8) |
- ((x & 0xff0000) >> 8) |
+ return ((x & 0xff) << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) |
((x & 0xff000000) >> 24);
}
static inline uint64_t
swapBytes(uint64_t x)
{
uint32_t a = x & UINT32_MAX;
uint32_t b = x >> 32;
return (uint64_t(swapBytes(a)) << 32) | swapBytes(b);
}
-template <typename DataType> struct DataToRepType { typedef DataType result; };
-template <> struct DataToRepType<int8_t> { typedef uint8_t result; };
-template <> struct DataToRepType<uint8_t> { typedef uint8_t result; };
-template <> struct DataToRepType<int16_t> { typedef uint16_t result; };
-template <> struct DataToRepType<uint16_t> { typedef uint16_t result; };
-template <> struct DataToRepType<int32_t> { typedef uint32_t result; };
-template <> struct DataToRepType<uint32_t> { typedef uint32_t result; };
-template <> struct DataToRepType<float> { typedef uint32_t result; };
-template <> struct DataToRepType<double> { typedef uint64_t result; };
+template<typename DataType>
+struct DataToRepType
+{
+ typedef DataType result;
+};
+template<>
+struct DataToRepType<int8_t>
+{
+ typedef uint8_t result;
+};
+template<>
+struct DataToRepType<uint8_t>
+{
+ typedef uint8_t result;
+};
+template<>
+struct DataToRepType<int16_t>
+{
+ typedef uint16_t result;
+};
+template<>
+struct DataToRepType<uint16_t>
+{
+ typedef uint16_t result;
+};
+template<>
+struct DataToRepType<int32_t>
+{
+ typedef uint32_t result;
+};
+template<>
+struct DataToRepType<uint32_t>
+{
+ typedef uint32_t result;
+};
+template<>
+struct DataToRepType<float>
+{
+ typedef uint32_t result;
+};
+template<>
+struct DataToRepType<double>
+{
+ typedef uint64_t result;
+};
static inline void
Memcpy(uint8_t* dest, uint8_t* src, size_t nbytes)
{
memcpy(dest, src, nbytes);
}
static inline void
@@ -393,44 +437,48 @@ Memcpy(uint8_t* dest, SharedMem<uint8_t*
}
static inline void
Memcpy(SharedMem<uint8_t*> dest, uint8_t* src, size_t nbytes)
{
jit::AtomicOperations::memcpySafeWhenRacy(dest, src, nbytes);
}
-template <typename DataType, typename BufferPtrType>
+template<typename DataType, typename BufferPtrType>
struct DataViewIO
{
typedef typename DataToRepType<DataType>::result ReadWriteType;
static void fromBuffer(DataType* dest, BufferPtrType unalignedBuffer, bool wantSwap)
{
- MOZ_ASSERT((reinterpret_cast<uintptr_t>(dest) & (Min<size_t>(MOZ_ALIGNOF(void*), sizeof(DataType)) - 1)) == 0);
- Memcpy((uint8_t*) dest, unalignedBuffer, sizeof(ReadWriteType));
+ MOZ_ASSERT((reinterpret_cast<uintptr_t>(dest) &
+ (Min<size_t>(MOZ_ALIGNOF(void*), sizeof(DataType)) - 1)) == 0);
+ Memcpy((uint8_t*)dest, unalignedBuffer, sizeof(ReadWriteType));
if (wantSwap) {
ReadWriteType* rwDest = reinterpret_cast<ReadWriteType*>(dest);
*rwDest = swapBytes(*rwDest);
}
}
static void toBuffer(BufferPtrType unalignedBuffer, const DataType* src, bool wantSwap)
{
- MOZ_ASSERT((reinterpret_cast<uintptr_t>(src) & (Min<size_t>(MOZ_ALIGNOF(void*), sizeof(DataType)) - 1)) == 0);
+ MOZ_ASSERT((reinterpret_cast<uintptr_t>(src) &
+ (Min<size_t>(MOZ_ALIGNOF(void*), sizeof(DataType)) - 1)) == 0);
ReadWriteType temp = *reinterpret_cast<const ReadWriteType*>(src);
if (wantSwap)
temp = swapBytes(temp);
- Memcpy(unalignedBuffer, (uint8_t*) &temp, sizeof(ReadWriteType));
+ Memcpy(unalignedBuffer, (uint8_t*)&temp, sizeof(ReadWriteType));
}
};
template<typename NativeType>
/* static */ bool
-DataViewObject::read(JSContext* cx, Handle<DataViewObject*> obj, const CallArgs& args,
+DataViewObject::read(JSContext* cx,
+ Handle<DataViewObject*> obj,
+ const CallArgs& args,
NativeType* val)
{
// Steps 1-2. done by the caller
// Step 3. unnecessary assert
// Step 4.
uint64_t getIndex;
if (!ToIndex(cx, args.get(0), &getIndex))
@@ -442,58 +490,58 @@ DataViewObject::read(JSContext* cx, Hand
// Steps 6-7.
if (obj->arrayBufferEither().isDetached()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
return false;
}
// Steps 8-12.
bool isSharedMemory;
- SharedMem<uint8_t*> data = DataViewObject::getDataPointer<NativeType>(cx, obj, getIndex,
- &isSharedMemory);
+ SharedMem<uint8_t*> data =
+ DataViewObject::getDataPointer<NativeType>(cx, obj, getIndex, &isSharedMemory);
if (!data)
return false;
// Step 13.
if (isSharedMemory) {
- DataViewIO<NativeType, SharedMem<uint8_t*>>::fromBuffer(val, data,
- needToSwapBytes(isLittleEndian));
+ DataViewIO<NativeType, SharedMem<uint8_t*>>::fromBuffer(
+ val, data, needToSwapBytes(isLittleEndian));
} else {
- DataViewIO<NativeType, uint8_t*>::fromBuffer(val, data.unwrapUnshared(),
- needToSwapBytes(isLittleEndian));
+ DataViewIO<NativeType, uint8_t*>::fromBuffer(
+ val, data.unwrapUnshared(), needToSwapBytes(isLittleEndian));
}
return true;
}
-template <typename NativeType>
+template<typename NativeType>
static inline bool
WebIDLCast(JSContext* cx, HandleValue value, NativeType* out)
{
int32_t temp;
if (!ToInt32(cx, value, &temp))
return false;
// Technically, the behavior of assigning an out of range value to a signed
// variable is undefined. In practice, compilers seem to do what we want
// without issuing any warnings.
*out = static_cast<NativeType>(temp);
return true;
}
-template <>
+template<>
inline bool
WebIDLCast<float>(JSContext* cx, HandleValue value, float* out)
{
double temp;
if (!ToNumber(cx, value, &temp))
return false;
*out = static_cast<float>(temp);
return true;
}
-template <>
+template<>
inline bool
WebIDLCast<double>(JSContext* cx, HandleValue value, double* out)
{
return ToNumber(cx, value, out);
}
template<typename NativeType>
/* static */ bool
@@ -524,28 +572,28 @@ DataViewObject::write(JSContext* cx, Han
// Steps 7-8.
if (obj->arrayBufferEither().isDetached()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
return false;
}
// Steps 9-13.
bool isSharedMemory;
- SharedMem<uint8_t*> data = DataViewObject::getDataPointer<NativeType>(cx, obj, getIndex,
- &isSharedMemory);
+ SharedMem<uint8_t*> data =
+ DataViewObject::getDataPointer<NativeType>(cx, obj, getIndex, &isSharedMemory);
if (!data)
return false;
// Step 14.
if (isSharedMemory) {
- DataViewIO<NativeType, SharedMem<uint8_t*>>::toBuffer(data, &value,
- needToSwapBytes(isLittleEndian));
+ DataViewIO<NativeType, SharedMem<uint8_t*>>::toBuffer(
+ data, &value, needToSwapBytes(isLittleEndian));
} else {
- DataViewIO<NativeType, uint8_t*>::toBuffer(data.unwrapUnshared(), &value,
- needToSwapBytes(isLittleEndian));
+ DataViewIO<NativeType, uint8_t*>::toBuffer(
+ data.unwrapUnshared(), &value, needToSwapBytes(isLittleEndian));
}
return true;
}
bool
DataViewObject::getInt8Impl(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(is(args.thisv()));
@@ -870,17 +918,16 @@ DataViewObject::setFloat64Impl(JSContext
bool
DataViewObject::fun_setFloat64(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<is, setFloat64Impl>(cx, args);
}
-
bool
DataViewObject::bufferGetterImpl(JSContext* cx, const CallArgs& args)
{
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
args.rval().set(DataViewObject::bufferValue(thisView));
return true;
}
@@ -916,79 +963,74 @@ DataViewObject::byteOffsetGetterImpl(JSC
bool
DataViewObject::byteOffsetGetter(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<is, byteOffsetGetterImpl>(cx, args);
}
-const Class DataViewObject::protoClass_ = {
- js_Object_str,
- JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
- JS_NULL_CLASS_OPS,
- &DataViewObject::classSpec_
-};
+const Class DataViewObject::protoClass_ = { js_Object_str,
+ JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
+ JS_NULL_CLASS_OPS,
+ &DataViewObject::classSpec_ };
JSObject*
DataViewObject::CreatePrototype(JSContext* cx, JSProtoKey key)
{
return GlobalObject::createBlankPrototype(cx, cx->global(), &DataViewObject::protoClass_);
}
-static const ClassOps DataViewObjectClassOps = {
- nullptr, /* addProperty */
- nullptr, /* delProperty */
- nullptr, /* getProperty */
- nullptr, /* setProperty */
- nullptr, /* enumerate */
- nullptr, /* resolve */
- nullptr, /* mayResolve */
- nullptr, /* finalize */
- nullptr, /* call */
- nullptr, /* hasInstance */
- nullptr, /* construct */
- ArrayBufferViewObject::trace
-};
+static const ClassOps DataViewObjectClassOps = { nullptr, /* addProperty */
+ nullptr, /* delProperty */
+ nullptr, /* getProperty */
+ nullptr, /* setProperty */
+ nullptr, /* enumerate */
+ nullptr, /* resolve */
+ nullptr, /* mayResolve */
+ nullptr, /* finalize */
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ ArrayBufferViewObject::trace };
const ClassSpec DataViewObject::classSpec_ = {
GenericCreateConstructor<DataViewObject::construct, 3, gc::AllocKind::FUNCTION>,
DataViewObject::CreatePrototype,
nullptr,
nullptr,
DataViewObject::methods,
DataViewObject::properties,
};
const Class DataViewObject::class_ = {
"DataView",
- JSCLASS_HAS_PRIVATE |
- JSCLASS_HAS_RESERVED_SLOTS(TypedArrayObject::RESERVED_SLOTS) |
- JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
+ JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(TypedArrayObject::RESERVED_SLOTS) |
+ JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
&DataViewObjectClassOps,
&DataViewObject::classSpec_
};
const JSFunctionSpec DataViewObject::methods[] = {
- JS_FN("getInt8", DataViewObject::fun_getInt8, 1,0),
- JS_FN("getUint8", DataViewObject::fun_getUint8, 1,0),
- JS_FN("getInt16", DataViewObject::fun_getInt16, 1,0),
- JS_FN("getUint16", DataViewObject::fun_getUint16, 1,0),
- JS_FN("getInt32", DataViewObject::fun_getInt32, 1,0),
- JS_FN("getUint32", DataViewObject::fun_getUint32, 1,0),
- JS_FN("getFloat32", DataViewObject::fun_getFloat32, 1,0),
- JS_FN("getFloat64", DataViewObject::fun_getFloat64, 1,0),
- JS_FN("setInt8", DataViewObject::fun_setInt8, 2,0),
- JS_FN("setUint8", DataViewObject::fun_setUint8, 2,0),
- JS_FN("setInt16", DataViewObject::fun_setInt16, 2,0),
- JS_FN("setUint16", DataViewObject::fun_setUint16, 2,0),
- JS_FN("setInt32", DataViewObject::fun_setInt32, 2,0),
- JS_FN("setUint32", DataViewObject::fun_setUint32, 2,0),
- JS_FN("setFloat32", DataViewObject::fun_setFloat32, 2,0),
- JS_FN("setFloat64", DataViewObject::fun_setFloat64, 2,0),
+ JS_FN("getInt8", DataViewObject::fun_getInt8, 1, 0),
+ JS_FN("getUint8", DataViewObject::fun_getUint8, 1, 0),
+ JS_FN("getInt16", DataViewObject::fun_getInt16, 1, 0),
+ JS_FN("getUint16", DataViewObject::fun_getUint16, 1, 0),
+ JS_FN("getInt32", DataViewObject::fun_getInt32, 1, 0),
+ JS_FN("getUint32", DataViewObject::fun_getUint32, 1, 0),
+ JS_FN("getFloat32", DataViewObject::fun_getFloat32, 1, 0),
+ JS_FN("getFloat64", DataViewObject::fun_getFloat64, 1, 0),
+ JS_FN("setInt8", DataViewObject::fun_setInt8, 2, 0),
+ JS_FN("setUint8", DataViewObject::fun_setUint8, 2, 0),
+ JS_FN("setInt16", DataViewObject::fun_setInt16, 2, 0),
+ JS_FN("setUint16", DataViewObject::fun_setUint16, 2, 0),
+ JS_FN("setInt32", DataViewObject::fun_setInt32, 2, 0),
+ JS_FN("setUint32", DataViewObject::fun_setUint32, 2, 0),
+ JS_FN("setFloat32", DataViewObject::fun_setFloat32, 2, 0),
+ JS_FN("setFloat64", DataViewObject::fun_setFloat64, 2, 0),
JS_FS_END
};
const JSPropertySpec DataViewObject::properties[] = {
JS_PSG("buffer", DataViewObject::bufferGetter, 0),
JS_PSG("byteLength", DataViewObject::byteLengthGetter, 0),
JS_PSG("byteOffset", DataViewObject::byteOffsetGetter, 0),
JS_STRING_SYM_PS(toStringTag, "DataView", JSPROP_READONLY),
--- a/js/src/builtin/DataViewObject.h
+++ b/js/src/builtin/DataViewObject.h
@@ -27,88 +27,102 @@ namespace js {
class DataViewObject : public NativeObject
{
private:
static const Class protoClass_;
static const ClassSpec classSpec_;
static JSObject* CreatePrototype(JSContext* cx, JSProtoKey key);
- static bool is(HandleValue v) {
- return v.isObject() && v.toObject().hasClass(&class_);
- }
+ static bool is(HandleValue v) { return v.isObject() && v.toObject().hasClass(&class_); }
- template <typename NativeType>
- static SharedMem<uint8_t*>
- getDataPointer(JSContext* cx, Handle<DataViewObject*> obj, uint64_t offset, bool* isSharedMemory);
+ template<typename NativeType>
+ static SharedMem<uint8_t*> getDataPointer(JSContext* cx,
+ Handle<DataViewObject*> obj,
+ uint64_t offset,
+ bool* isSharedMemory);
static bool bufferGetterImpl(JSContext* cx, const CallArgs& args);
static bool bufferGetter(JSContext* cx, unsigned argc, Value* vp);
static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args);
static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
static bool byteOffsetGetterImpl(JSContext* cx, const CallArgs& args);
static bool byteOffsetGetter(JSContext* cx, unsigned argc, Value* vp);
- static bool
- getAndCheckConstructorArgs(JSContext* cx, HandleObject bufobj, const CallArgs& args,
- uint32_t* byteOffset, uint32_t* byteLength);
+ static bool getAndCheckConstructorArgs(JSContext* cx,
+ HandleObject bufobj,
+ const CallArgs& args,
+ uint32_t* byteOffset,
+ uint32_t* byteLength);
static bool constructSameCompartment(JSContext* cx, HandleObject bufobj, const CallArgs& args);
static bool constructWrapped(JSContext* cx, HandleObject bufobj, const CallArgs& args);
- static DataViewObject*
- create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
- Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, JSObject* proto);
+ static DataViewObject* create(JSContext* cx,
+ uint32_t byteOffset,
+ uint32_t byteLength,
+ Handle<ArrayBufferObjectMaybeShared*> arrayBuffer,
+ JSObject* proto);
public:
static const Class class_;
- static Value byteOffsetValue(DataViewObject* view) {
+ static Value byteOffsetValue(DataViewObject* view)
+ {
Value v = view->getFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT);
MOZ_ASSERT(v.toInt32() >= 0);
return v;
}
- static Value byteLengthValue(DataViewObject* view) {
+ static Value byteLengthValue(DataViewObject* view)
+ {
Value v = view->getFixedSlot(TypedArrayObject::LENGTH_SLOT);
MOZ_ASSERT(v.toInt32() >= 0);
return v;
}
- static Value bufferValue(DataViewObject* view) {
+ static Value bufferValue(DataViewObject* view)
+ {
return view->getFixedSlot(TypedArrayObject::BUFFER_SLOT);
}
- uint32_t byteOffset() const {
+ uint32_t byteOffset() const
+ {
return byteOffsetValue(const_cast<DataViewObject*>(this)).toInt32();
}
- uint32_t byteLength() const {
+ uint32_t byteLength() const
+ {
return byteLengthValue(const_cast<DataViewObject*>(this)).toInt32();
}
- ArrayBufferObjectMaybeShared& arrayBufferEither() const {
- return bufferValue(
- const_cast<DataViewObject*>(this)).toObject().as<ArrayBufferObjectMaybeShared>();
+ ArrayBufferObjectMaybeShared& arrayBufferEither() const
+ {
+ return bufferValue(const_cast<DataViewObject*>(this))
+ .toObject()
+ .as<ArrayBufferObjectMaybeShared>();
}
- SharedMem<void*> dataPointerEither() const {
- void *p = getPrivate();
+ SharedMem<void*> dataPointerEither() const
+ {
+ void* p = getPrivate();
if (isSharedMemory())
return SharedMem<void*>::shared(p);
return SharedMem<void*>::unshared(p);
}
- void* dataPointerUnshared() const {
+ void* dataPointerUnshared() const
+ {
MOZ_ASSERT(!isSharedMemory());
return getPrivate();
}
- void* dataPointerShared() const {
+ void* dataPointerShared() const
+ {
MOZ_ASSERT(isSharedMemory());
return getPrivate();
}
static bool construct(JSContext* cx, unsigned argc, Value* vp);
static bool getInt8Impl(JSContext* cx, const CallArgs& args);
static bool fun_getInt8(JSContext* cx, unsigned argc, Value* vp);
@@ -156,17 +170,19 @@ class DataViewObject : public NativeObje
static bool fun_setFloat32(JSContext* cx, unsigned argc, Value* vp);
static bool setFloat64Impl(JSContext* cx, const CallArgs& args);
static bool fun_setFloat64(JSContext* cx, unsigned argc, Value* vp);
static bool initClass(JSContext* cx);
static void notifyBufferDetached(JSObject* view);
template<typename NativeType>
- static bool read(JSContext* cx, Handle<DataViewObject*> obj, const CallArgs& args,
+ static bool read(JSContext* cx,
+ Handle<DataViewObject*> obj,
+ const CallArgs& args,
NativeType* val);
template<typename NativeType>
static bool write(JSContext* cx, Handle<DataViewObject*> obj, const CallArgs& args);
void notifyBufferDetached(void* newData);
private:
static const JSFunctionSpec methods[];
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -38,64 +38,66 @@ AssertInnerizedEnvironmentChain(JSContex
#endif
}
static bool
IsEvalCacheCandidate(JSScript* script)
{
// Make sure there are no inner objects which might use the wrong parent
// and/or call scope by reusing the previous eval's script.
- return script->isDirectEvalInFunction() &&
- !script->hasSingletons() &&
- !script->hasObjects();
+ return script->isDirectEvalInFunction() && !script->hasSingletons() && !script->hasObjects();
}
/* static */ HashNumber
EvalCacheHashPolicy::hash(const EvalCacheLookup& l)
{
AutoCheckCannotGC nogc;
uint32_t hash = l.str->hasLatin1Chars()
- ? HashString(l.str->latin1Chars(nogc), l.str->length())
- : HashString(l.str->twoByteChars(nogc), l.str->length());
+ ? HashString(l.str->latin1Chars(nogc), l.str->length())
+ : HashString(l.str->twoByteChars(nogc), l.str->length());
return AddToHash(hash, l.callerScript.get(), l.version, l.pc);
}
/* static */ bool
EvalCacheHashPolicy::match(const EvalCacheEntry& cacheEntry, const EvalCacheLookup& l)
{
JSScript* script = cacheEntry.script;
MOZ_ASSERT(IsEvalCacheCandidate(script));
- return EqualStrings(cacheEntry.str, l.str) &&
- cacheEntry.callerScript == l.callerScript &&
- script->getVersion() == l.version &&
- cacheEntry.pc == l.pc;
+ return EqualStrings(cacheEntry.str, l.str) && cacheEntry.callerScript == l.callerScript &&
+ script->getVersion() == l.version && cacheEntry.pc == l.pc;
}
// Add the script to the eval cache when EvalKernel is finished
class EvalScriptGuard
{
JSContext* cx_;
Rooted<JSScript*> script_;
/* These fields are only valid if lookup_.str is non-nullptr. */
EvalCacheLookup lookup_;
mozilla::Maybe<DependentAddPtr<EvalCache>> p_;
RootedLinearString lookupStr_;
public:
explicit EvalScriptGuard(JSContext* cx)
- : cx_(cx), script_(cx), lookup_(cx), lookupStr_(cx) {}
+ : cx_(cx)
+ , script_(cx)
+ , lookup_(cx)
+ , lookupStr_(cx)
+ {
+ }
- ~EvalScriptGuard() {
+ ~EvalScriptGuard()
+ {
if (script_ && !cx_->isExceptionPending()) {
script_->cacheForEval();
- EvalCacheEntry cacheEntry = {lookupStr_, script_, lookup_.callerScript, lookup_.pc};
+ EvalCacheEntry cacheEntry = { lookupStr_, script_, lookup_.callerScript, lookup_.pc };
lookup_.str = lookupStr_;
if (lookup_.str && IsEvalCacheCandidate(script_)) {
// Ignore failure to add cache entry.
if (!p_->add(cx_, cx_->caches().evalCache, lookup_, cacheEntry))
cx_->recoverFromOutOfMemory();
}
}
}
@@ -110,87 +112,86 @@ class EvalScriptGuard
p_.emplace(cx_, cx_->caches().evalCache, lookup_);
if (*p_) {
script_ = (*p_)->script;
p_->remove(cx_, cx_->caches().evalCache, lookup_);
script_->uncacheForEval();
}
}
- void setNewScript(JSScript* script) {
+ void setNewScript(JSScript* script)
+ {
// JSScript::initFromEmitter has already called js_CallNewScriptHook.
MOZ_ASSERT(!script_ && script);
script_ = script;
script_->setActiveEval();
}
- bool foundScript() {
- return !!script_;
- }
+ bool foundScript() { return !!script_; }
- HandleScript script() {
+ HandleScript script()
+ {
MOZ_ASSERT(script_);
return script_;
}
};
-enum EvalJSONResult {
+enum EvalJSONResult
+{
EvalJSON_Failure,
EvalJSON_Success,
EvalJSON_NotJSON
};
-template <typename CharT>
+template<typename CharT>
static bool
EvalStringMightBeJSON(const mozilla::Range<const CharT> chars)
{
// If the eval string starts with '(' or '[' and ends with ')' or ']', it may be JSON.
// Try the JSON parser first because it's much faster. If the eval string
// isn't JSON, JSON parsing will probably fail quickly, so little time
// will be lost.
size_t length = chars.length();
- if (length > 2 &&
- ((chars[0] == '[' && chars[length - 1] == ']') ||
- (chars[0] == '(' && chars[length - 1] == ')')))
- {
+ if (length > 2 && ((chars[0] == '[' && chars[length - 1] == ']') ||
+ (chars[0] == '(' && chars[length - 1] == ')'))) {
// Remarkably, JavaScript syntax is not a superset of JSON syntax:
// strings in JavaScript cannot contain the Unicode line and paragraph
// terminator characters U+2028 and U+2029, but strings in JSON can.
// Rather than force the JSON parser to handle this quirk when used by
// eval, we simply don't use the JSON parser when either character
// appears in the provided string. See bug 657367.
if (sizeof(CharT) > 1) {
- for (RangedPtr<const CharT> cp = chars.begin() + 1, end = chars.end() - 1;
- cp < end;
- cp++)
- {
+ for (RangedPtr<const CharT> cp = chars.begin() + 1, end = chars.end() - 1; cp < end;
+ cp++) {
char16_t c = *cp;
if (c == 0x2028 || c == 0x2029)
return false;
}
}
return true;
}
return false;
}
-template <typename CharT>
+template<typename CharT>
static EvalJSONResult
-ParseEvalStringAsJSON(JSContext* cx, const mozilla::Range<const CharT> chars, MutableHandleValue rval)
+ParseEvalStringAsJSON(JSContext* cx,
+ const mozilla::Range<const CharT> chars,
+ MutableHandleValue rval)
{
size_t len = chars.length();
MOZ_ASSERT((chars[0] == '(' && chars[len - 1] == ')') ||
(chars[0] == '[' && chars[len - 1] == ']'));
- auto jsonChars = (chars[0] == '[')
- ? chars
- : mozilla::Range<const CharT>(chars.begin().get() + 1U, len - 2);
+ auto jsonChars =
+ (chars[0] == '[') ? chars : mozilla::Range<const CharT>(chars.begin().get() + 1U, len - 2);
- Rooted<JSONParser<CharT>> parser(cx, JSONParser<CharT>(cx, jsonChars, JSONParserBase::NoError));
+ Rooted<JSONParser<CharT>> parser(cx,
+ JSONParser<CharT>(cx, jsonChars, JSONParserBase::NoError));
if (!parser.parse(rval))
return EvalJSON_Failure;
return rval.isUndefined() ? EvalJSON_NotJSON : EvalJSON_Success;
}
static EvalJSONResult
TryEvalJSON(JSContext* cx, JSLinearString* str, MutableHandleValue rval)
@@ -204,34 +205,42 @@ TryEvalJSON(JSContext* cx, JSLinearStrin
if (!EvalStringMightBeJSON(str->twoByteRange(nogc)))
return EvalJSON_NotJSON;
}
AutoStableStringChars linearChars(cx);
if (!linearChars.init(cx, str))
return EvalJSON_Failure;
- return linearChars.isLatin1()
- ? ParseEvalStringAsJSON(cx, linearChars.latin1Range(), rval)
- : ParseEvalStringAsJSON(cx, linearChars.twoByteRange(), rval);
+ return linearChars.isLatin1() ? ParseEvalStringAsJSON(cx, linearChars.latin1Range(), rval)
+ : ParseEvalStringAsJSON(cx, linearChars.twoByteRange(), rval);
}
-enum EvalType { DIRECT_EVAL, INDIRECT_EVAL };
+enum EvalType
+{
+ DIRECT_EVAL,
+ INDIRECT_EVAL
+};
// Common code implementing direct and indirect eval.
//
// Evaluate call.argv[2], if it is a string, in the context of the given calling
// frame, with the provided scope chain, with the semantics of either a direct
// or indirect eval (see ES5 10.4.2). If this is an indirect eval, env
// must be a global object.
//
// On success, store the completion value in call.rval and return true.
static bool
-EvalKernel(JSContext* cx, HandleValue v, EvalType evalType, AbstractFramePtr caller,
- HandleObject env, jsbytecode* pc, MutableHandleValue vp)
+EvalKernel(JSContext* cx,
+ HandleValue v,
+ EvalType evalType,
+ AbstractFramePtr caller,
+ HandleObject env,
+ jsbytecode* pc,
+ MutableHandleValue vp)
{
MOZ_ASSERT((evalType == INDIRECT_EVAL) == !caller);
MOZ_ASSERT((evalType == INDIRECT_EVAL) == !pc);
MOZ_ASSERT_IF(evalType == INDIRECT_EVAL, IsGlobalLexicalEnvironment(env));
AssertInnerizedEnvironmentChain(cx, *env);
Rooted<GlobalObject*> envGlobal(cx, &env->global());
if (!GlobalObject::isRuntimeCodeGenEnabled(cx, envGlobal)) {
@@ -269,75 +278,80 @@ EvalKernel(JSContext* cx, HandleValue v,
esg.lookupInEvalCache(linearStr, callerScript, pc);
if (!esg.foundScript()) {
RootedScript maybeScript(cx);
unsigned lineno;
const char* filename;
bool mutedErrors;
uint32_t pcOffset;
- DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno, &pcOffset,
+ DescribeScriptedCallerForCompilation(cx,
+ &maybeScript,
+ &filename,
+ &lineno,
+ &pcOffset,
&mutedErrors,
- evalType == DIRECT_EVAL
- ? CALLED_FROM_JSOP_EVAL
- : NOT_CALLED_FROM_JSOP_EVAL);
+ evalType == DIRECT_EVAL ? CALLED_FROM_JSOP_EVAL
+ : NOT_CALLED_FROM_JSOP_EVAL);
const char* introducerFilename = filename;
if (maybeScript && maybeScript->scriptSource()->introducerFilename())
introducerFilename = maybeScript->scriptSource()->introducerFilename();
RootedScope enclosing(cx);
if (evalType == DIRECT_EVAL)
enclosing = callerScript->innermostScope(pc);
else
enclosing = &cx->global()->emptyGlobalScope();
CompileOptions options(cx);
options.setIsRunOnce(true)
- .setNoScriptRval(false)
- .setMutedErrors(mutedErrors)
- .maybeMakeStrictMode(evalType == DIRECT_EVAL && IsStrictEvalPC(pc));
+ .setNoScriptRval(false)
+ .setMutedErrors(mutedErrors)
+ .maybeMakeStrictMode(evalType == DIRECT_EVAL && IsStrictEvalPC(pc));
if (introducerFilename) {
options.setFileAndLine(filename, 1);
options.setIntroductionInfo(introducerFilename, "eval", lineno, maybeScript, pcOffset);
} else {
options.setFileAndLine("eval", 1);
options.setIntroductionType("eval");
}
AutoStableStringChars linearChars(cx);
if (!linearChars.initTwoByte(cx, linearStr))
return false;
const char16_t* chars = linearChars.twoByteRange().begin().get();
SourceBufferHolder::Ownership ownership = linearChars.maybeGiveOwnershipToCaller()
- ? SourceBufferHolder::GiveOwnership
- : SourceBufferHolder::NoOwnership;
+ ? SourceBufferHolder::GiveOwnership
+ : SourceBufferHolder::NoOwnership;
SourceBufferHolder srcBuf(chars, linearStr->length(), ownership);
- JSScript* compiled = frontend::CompileEvalScript(cx, cx->tempLifoAlloc(),
- env, enclosing,
- options, srcBuf);
+ JSScript* compiled =
+ frontend::CompileEvalScript(cx, cx->tempLifoAlloc(), env, enclosing, options, srcBuf);
if (!compiled)
return false;
esg.setNewScript(compiled);
}
// Look up the newTarget from the frame iterator.
Value newTargetVal = NullValue();
- return ExecuteKernel(cx, esg.script(), *env, newTargetVal,
- NullFramePtr() /* evalInFrame */, vp.address());
+ return ExecuteKernel(
+ cx, esg.script(), *env, newTargetVal, NullFramePtr() /* evalInFrame */, vp.address());
}
bool
js::DirectEvalStringFromIon(JSContext* cx,
- HandleObject env, HandleScript callerScript,
- HandleValue newTargetValue, HandleString str,
- jsbytecode* pc, MutableHandleValue vp)
+ HandleObject env,
+ HandleScript callerScript,
+ HandleValue newTargetValue,
+ HandleString str,
+ jsbytecode* pc,
+ MutableHandleValue vp)
{
AssertInnerizedEnvironmentChain(cx, *env);
Rooted<GlobalObject*> envGlobal(cx, &env->global());
if (!GlobalObject::isRuntimeCodeGenEnabled(cx, envGlobal)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_EVAL);
return false;
}
@@ -357,100 +371,99 @@ js::DirectEvalStringFromIon(JSContext* c
esg.lookupInEvalCache(linearStr, callerScript, pc);
if (!esg.foundScript()) {
RootedScript maybeScript(cx);
const char* filename;
unsigned lineno;
bool mutedErrors;
uint32_t pcOffset;
- DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno, &pcOffset,
- &mutedErrors, CALLED_FROM_JSOP_EVAL);
+ DescribeScriptedCallerForCompilation(
+ cx, &maybeScript, &filename, &lineno, &pcOffset, &mutedErrors, CALLED_FROM_JSOP_EVAL);
const char* introducerFilename = filename;
if (maybeScript && maybeScript->scriptSource()->introducerFilename())
introducerFilename = maybeScript->scriptSource()->introducerFilename();
RootedScope enclosing(cx, callerScript->innermostScope(pc));
CompileOptions options(cx);
options.setIsRunOnce(true)
- .setNoScriptRval(false)
- .setMutedErrors(mutedErrors)
- .maybeMakeStrictMode(IsStrictEvalPC(pc));
+ .setNoScriptRval(false)
+ .setMutedErrors(mutedErrors)
+ .maybeMakeStrictMode(IsStrictEvalPC(pc));
if (introducerFilename) {
options.setFileAndLine(filename, 1);
options.setIntroductionInfo(introducerFilename, "eval", lineno, maybeScript, pcOffset);
} else {
options.setFileAndLine("eval", 1);
options.setIntroductionType("eval");
}
AutoStableStringChars linearChars(cx);
if (!linearChars.initTwoByte(cx, linearStr))
return false;
const char16_t* chars = linearChars.twoByteRange().begin().get();
SourceBufferHolder::Ownership ownership = linearChars.maybeGiveOwnershipToCaller()
- ? SourceBufferHolder::GiveOwnership
- : SourceBufferHolder::NoOwnership;
+ ? SourceBufferHolder::GiveOwnership
+ : SourceBufferHolder::NoOwnership;
SourceBufferHolder srcBuf(chars, linearStr->length(), ownership);
- JSScript* compiled = frontend::CompileEvalScript(cx, cx->tempLifoAlloc(),
- env, enclosing,
- options, srcBuf);
+ JSScript* compiled =
+ frontend::CompileEvalScript(cx, cx->tempLifoAlloc(), env, enclosing, options, srcBuf);
if (!compiled)
return false;
esg.setNewScript(compiled);
}
- return ExecuteKernel(cx, esg.script(), *env, newTargetValue,
- NullFramePtr() /* evalInFrame */, vp.address());
+ return ExecuteKernel(
+ cx, esg.script(), *env, newTargetValue, NullFramePtr() /* evalInFrame */, vp.address());
}
bool
js::IndirectEval(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<GlobalObject*> global(cx, &args.callee().global());
RootedObject globalLexical(cx, &global->lexicalEnvironment());
// Note we'll just pass |undefined| here, then return it directly (or throw
// if runtime codegen is disabled), if no argument is provided.