// Copyright 2016 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. #include "src/base/macros.h" #include "src/base/platform/mutex.h" #include "src/base/platform/time.h" #include "src/builtins/builtins-utils-inl.h" #include "src/builtins/builtins.h" #include "src/code-factory.h" #include "src/conversions-inl.h" #include "src/counters.h" #include "src/futex-emulation.h" #include "src/globals.h" #include "src/heap/factory.h" #include "src/objects-inl.h" #include "src/objects/js-array-buffer-inl.h" namespace v8 { namespace internal { // See builtins-arraybuffer.cc for implementations of // SharedArrayBuffer.prototye.byteLength and SharedArrayBuffer.prototype.slice inline bool AtomicIsLockFree(uint32_t size) { return size == 1 || size == 2 || size == 4; } // ES #sec-atomics.islockfree BUILTIN(AtomicsIsLockFree) { HandleScope scope(isolate); Handle<Object> size = args.atOrUndefined(isolate, 1); ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, size, Object::ToNumber(isolate, size)); return *isolate->factory()->ToBoolean(AtomicIsLockFree(size->Number())); } // ES #sec-validatesharedintegertypedarray V8_WARN_UNUSED_RESULT MaybeHandle<JSTypedArray> ValidateSharedIntegerTypedArray( Isolate* isolate, Handle<Object> object, bool only_int32 = false) { if (object->IsJSTypedArray()) { Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(object); if (typed_array->GetBuffer()->is_shared()) { if (only_int32) { if (typed_array->type() == kExternalInt32Array) return typed_array; } else { if (typed_array->type() != kExternalFloat32Array && typed_array->type() != kExternalFloat64Array && typed_array->type() != kExternalUint8ClampedArray) return typed_array; } } } THROW_NEW_ERROR( isolate, NewTypeError(only_int32 ? MessageTemplate::kNotInt32SharedTypedArray : MessageTemplate::kNotIntegerSharedTypedArray, object), JSTypedArray); } // ES #sec-validateatomicaccess // ValidateAtomicAccess( typedArray, requestIndex ) V8_WARN_UNUSED_RESULT Maybe<size_t> ValidateAtomicAccess( Isolate* isolate, Handle<JSTypedArray> typed_array, Handle<Object> request_index) { Handle<Object> access_index_obj; ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate, access_index_obj, Object::ToIndex(isolate, request_index, MessageTemplate::kInvalidAtomicAccessIndex), Nothing<size_t>()); size_t access_index; if (!TryNumberToSize(*access_index_obj, &access_index) || access_index >= typed_array->length_value()) { isolate->Throw(*isolate->factory()->NewRangeError( MessageTemplate::kInvalidAtomicAccessIndex)); return Nothing<size_t>(); } return Just<size_t>(access_index); } // ES #sec-atomics.wake // Atomics.wake( typedArray, index, count ) BUILTIN(AtomicsWake) { HandleScope scope(isolate); Handle<Object> array = args.atOrUndefined(isolate, 1); Handle<Object> index = args.atOrUndefined(isolate, 2); Handle<Object> count = args.atOrUndefined(isolate, 3); Handle<JSTypedArray> sta; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, sta, ValidateSharedIntegerTypedArray(isolate, array, true)); Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index); if (maybe_index.IsNothing()) return ReadOnlyRoots(isolate).exception(); size_t i = maybe_index.FromJust(); uint32_t c; if (count->IsUndefined(isolate)) { c = kMaxUInt32; } else { ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, count, Object::ToInteger(isolate, count)); double count_double = count->Number(); if (count_double < 0) count_double = 0; else if (count_double > kMaxUInt32) count_double = kMaxUInt32; c = static_cast<uint32_t>(count_double); } Handle<JSArrayBuffer> array_buffer = sta->GetBuffer(); size_t addr = (i << 2) + NumberToSize(sta->byte_offset()); return FutexEmulation::Wake(array_buffer, addr, c); } // ES #sec-atomics.wait // Atomics.wait( typedArray, index, value, timeout ) BUILTIN(AtomicsWait) { HandleScope scope(isolate); Handle<Object> array = args.atOrUndefined(isolate, 1); Handle<Object> index = args.atOrUndefined(isolate, 2); Handle<Object> value = args.atOrUndefined(isolate, 3); Handle<Object> timeout = args.atOrUndefined(isolate, 4); Handle<JSTypedArray> sta; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, sta, ValidateSharedIntegerTypedArray(isolate, array, true)); Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index); if (maybe_index.IsNothing()) return ReadOnlyRoots(isolate).exception(); size_t i = maybe_index.FromJust(); ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToInt32(isolate, value)); int32_t value_int32 = NumberToInt32(*value); double timeout_number; if (timeout->IsUndefined(isolate)) { timeout_number = ReadOnlyRoots(isolate).infinity_value()->Number(); } else { ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, timeout, Object::ToNumber(isolate, timeout)); timeout_number = timeout->Number(); if (std::isnan(timeout_number)) timeout_number = ReadOnlyRoots(isolate).infinity_value()->Number(); else if (timeout_number < 0) timeout_number = 0; } if (!isolate->allow_atomics_wait()) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError(MessageTemplate::kAtomicsWaitNotAllowed)); } Handle<JSArrayBuffer> array_buffer = sta->GetBuffer(); size_t addr = (i << 2) + NumberToSize(sta->byte_offset()); return FutexEmulation::Wait(isolate, array_buffer, addr, value_int32, timeout_number); } } // namespace internal } // namespace v8