Index: src/runtime.cc |
diff --git a/src/runtime.cc b/src/runtime.cc |
index f2e2650ce7d9e7c7c5a6d1c266a8ffead5f8e24a..3c9d0072ad0a70402553fee675ee6714e6020953 100644 |
--- a/src/runtime.cc |
+++ b/src/runtime.cc |
@@ -25,6 +25,7 @@ |
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+#include <pthread.h> |
#include <stdlib.h> |
#include <limits> |
@@ -783,7 +784,8 @@ void Runtime::SetupArrayBuffer(Isolate* isolate, |
Handle<JSArrayBuffer> array_buffer, |
bool is_external, |
void* data, |
- size_t allocated_length) { |
+ size_t allocated_length, |
+ bool shared) { |
ASSERT(array_buffer->GetInternalFieldCount() == |
v8::ArrayBuffer::kInternalFieldCount); |
for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) { |
@@ -792,6 +794,7 @@ void Runtime::SetupArrayBuffer(Isolate* isolate, |
array_buffer->set_backing_store(data); |
array_buffer->set_flag(Smi::FromInt(0)); |
array_buffer->set_is_external(is_external); |
+ array_buffer->set_is_shared(shared); |
Handle<Object> byte_length = |
isolate->factory()->NewNumberFromSize(allocated_length); |
@@ -808,7 +811,8 @@ bool Runtime::SetupArrayBufferAllocatingData( |
Isolate* isolate, |
Handle<JSArrayBuffer> array_buffer, |
size_t allocated_length, |
- bool initialize) { |
+ bool initialize, |
+ bool shared) { |
void* data; |
CHECK(V8::ArrayBufferAllocator() != NULL); |
if (allocated_length != 0) { |
@@ -823,7 +827,8 @@ bool Runtime::SetupArrayBufferAllocatingData( |
data = NULL; |
} |
- SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length); |
+ SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length, |
+ shared); |
isolate->heap()->AdjustAmountOfExternalAllocatedMemory(allocated_length); |
@@ -851,9 +856,13 @@ void Runtime::NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer) { |
RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferInitialize) { |
HandleScope scope(isolate); |
- ASSERT(args.length() == 2); |
+ ASSERT(args.length() == 3); |
CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); |
CONVERT_ARG_HANDLE_CHECKED(Object, byteLength, 1); |
+ CONVERT_BOOLEAN_ARG_CHECKED(shared, 2); |
+ |
+ // PrintF("Shared? %d\n", shared); |
+ |
size_t allocated_length; |
if (byteLength->IsSmi()) { |
allocated_length = Smi::cast(*byteLength)->value(); |
@@ -873,7 +882,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferInitialize) { |
} |
if (!Runtime::SetupArrayBufferAllocatingData(isolate, |
- holder, allocated_length)) { |
+ holder, allocated_length, true, |
+ shared)) { |
return isolate->Throw(*isolate->factory()-> |
NewRangeError("invalid_array_buffer_length", |
HandleVector<Object>(NULL, 0))); |
@@ -891,6 +901,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferGetByteLength) { |
} |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferGetShared) { |
+ SealHandleScope shs(isolate); |
+ ASSERT(args.length() == 1); |
+ CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0); |
+ return isolate->heap()->ToBoolean(holder->is_shared()); |
+} |
+ |
+ |
RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) { |
HandleScope scope(isolate); |
ASSERT(args.length() == 3); |
@@ -921,6 +939,382 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferIsView) { |
: isolate->heap()->false_value(); |
} |
+#if !defined(_POSIX_BARRIERS) || _POSIX_BARRIERS <= 0 |
+ |
+typedef int pthread_barrierattr_t; |
+ |
+ |
+typedef struct { |
+ pthread_mutex_t m; |
+ pthread_cond_t c; |
+ unsigned int maxCount; |
+ unsigned int currentCount; |
+} pthread_barrier_t; |
+ |
+ |
+int pthread_barrier_init(pthread_barrier_t *barrier, |
+ const pthread_barrierattr_t *attr, |
+ unsigned int count) { |
+ if (count == 0) { |
+ return 22; // EINVAL |
+ } |
+ |
+ int err = pthread_mutex_init(&barrier->m, NULL); |
+ if (err) { |
+ return err; |
+ } |
+ |
+ err = pthread_cond_init(&barrier->c, NULL); |
+ if (err) { |
+ pthread_mutex_destroy(&barrier->m); |
+ return err; |
+ } |
+ |
+ barrier->maxCount = count; |
+ barrier->currentCount = 0; |
+ |
+ return 0; |
+} |
+ |
+int pthread_barrier_destroy(pthread_barrier_t *barrier) { |
+ int cerr = pthread_cond_destroy(&barrier->c); |
+ int merr = pthread_mutex_destroy(&barrier->m); |
+ return merr || cerr; |
+} |
+ |
+#define PTHREAD_BARRIER_SERIAL_THREAD 1 |
+ |
+int pthread_barrier_wait(pthread_barrier_t *barrier) { |
+ pthread_mutex_lock(&barrier->m); |
+ barrier->currentCount += 1; |
+ if (barrier->currentCount >= barrier->maxCount) { |
+ barrier->currentCount = 0; |
+ pthread_cond_broadcast(&barrier->c); |
+ pthread_mutex_unlock(&barrier->m); |
+ return PTHREAD_BARRIER_SERIAL_THREAD; |
+ } else { |
+ pthread_cond_wait(&barrier->c, &barrier->m); |
+ pthread_mutex_unlock(&barrier->m); |
+ return 0; |
+ } |
+} |
+ |
+#endif |
+ |
+#define MUTEX_SIZE (sizeof(pthread_mutex_t)) |
+#define COND_SIZE (sizeof(pthread_cond_t)) |
+#define BARRIER_SIZE (sizeof(pthread_barrier_t)) |
+ |
+pthread_mutex_t* MutexAddr(Isolate *isolate, |
+ const Handle<JSArrayBuffer>& buffer, |
+ const Handle<Object>& offset) { |
+ size_t byte_offset; |
+ if (!TryNumberToSize(isolate, *offset, &byte_offset)) { |
+ return 0; |
+ } |
+ size_t byte_length = NumberToSize(isolate, buffer->byte_length()); |
+ if (byte_offset >= byte_length || byte_offset + MUTEX_SIZE > byte_length) { |
+ // overflow |
+ return 0; |
+ } |
+ // TODO(ncbray): alignment |
+ pthread_mutex_t* m = reinterpret_cast<pthread_mutex_t*>( |
+ reinterpret_cast<char*>(buffer->backing_store()) + byte_offset); |
+ return m; |
+} |
+ |
+ |
+pthread_cond_t* CondAddr(Isolate *isolate, |
+ const Handle<JSArrayBuffer>& buffer, |
+ const Handle<Object>& offset) { |
+ size_t byte_offset; |
+ if (!TryNumberToSize(isolate, *offset, &byte_offset)) { |
+ return 0; |
+ } |
+ size_t byte_length = NumberToSize(isolate, buffer->byte_length()); |
+ if (byte_offset >= byte_length || byte_offset + COND_SIZE > byte_length) { |
+ // overflow |
+ return 0; |
+ } |
+ // TODO(ncbray): alignment |
+ pthread_cond_t* c = reinterpret_cast<pthread_cond_t*>( |
+ reinterpret_cast<char*>(buffer->backing_store()) + byte_offset); |
+ return c; |
+} |
+ |
+ |
+pthread_barrier_t* BarrierAddr(Isolate *isolate, |
+ const Handle<JSArrayBuffer>& buffer, |
+ const Handle<Object>& offset) { |
+ size_t byte_offset; |
+ if (!TryNumberToSize(isolate, *offset, &byte_offset)) { |
+ return 0; |
+ } |
+ size_t byte_length = NumberToSize(isolate, buffer->byte_length()); |
+ if (byte_offset >= byte_length || byte_offset + BARRIER_SIZE > byte_length) { |
+ // overflow |
+ return 0; |
+ } |
+ // TODO(ncbray): alignment |
+ pthread_barrier_t* b = reinterpret_cast<pthread_barrier_t*>( |
+ reinterpret_cast<char*>(buffer->backing_store()) + byte_offset); |
+ return b; |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferMutexInit) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 2); |
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); |
+ |
+ pthread_mutex_t* m = MutexAddr(isolate, holder, offset); |
+ if (!m) { |
+ return Smi::FromInt(1); |
+ } |
+ |
+ //printf("Mutex init %p\n", m); |
+ int err = pthread_mutex_init(m, NULL); |
+ //printf("Mutex init done.\n"); |
+ |
+ return Smi::FromInt(err); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferMutexDestroy) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 2); |
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); |
+ |
+ pthread_mutex_t* m = MutexAddr(isolate, holder, offset); |
+ if (!m) { |
+ return Smi::FromInt(1); |
+ } |
+ |
+ //printf("Mutex destroy %p\n", m); |
+ int err = pthread_mutex_destroy(m); |
+ //printf("Mutex destroy done.\n"); |
+ |
+ return Smi::FromInt(err); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferMutexLock) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 2); |
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); |
+ |
+ pthread_mutex_t* m = MutexAddr(isolate, holder, offset); |
+ if (!m) { |
+ return Smi::FromInt(1); |
+ } |
+ |
+ //printf("Mutex lock %p\n", m); |
+ int err = pthread_mutex_lock(m); |
+ //printf("Mutex lock done.\n"); |
+ |
+ return Smi::FromInt(err); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferMutexUnlock) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 2); |
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); |
+ |
+ pthread_mutex_t* m = MutexAddr(isolate, holder, offset); |
+ if (!m) { |
+ return Smi::FromInt(1); |
+ } |
+ |
+ //printf("Mutex unlock %p\n", m); |
+ int err = pthread_mutex_unlock(m); |
+ //printf("Mutex unlock done.\n"); |
+ |
+ return Smi::FromInt(err); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferMutexSize) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 1); |
+ return Smi::FromInt(MUTEX_SIZE); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferCondInit) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 2); |
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); |
+ |
+ pthread_cond_t* c = CondAddr(isolate, holder, offset); |
+ if (!c) { |
+ return Smi::FromInt(1); |
+ } |
+ |
+ //printf("Cond init %p\n", c); |
+ int err = pthread_cond_init(c, NULL); |
+ //printf("Cond init done.\n"); |
+ return Smi::FromInt(err); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferCondDestroy) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 2); |
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); |
+ |
+ pthread_cond_t* c = CondAddr(isolate, holder, offset); |
+ if (!c) { |
+ return Smi::FromInt(1); |
+ } |
+ |
+ //printf("Cond destroy %p\n", c); |
+ int err = pthread_cond_destroy(c); |
+ //printf("Cond destroy done.\n"); |
+ return Smi::FromInt(err); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferCondWait) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 3); |
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, coffset, 1); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, moffset, 2); |
+ |
+ pthread_cond_t* c = CondAddr(isolate, holder, coffset); |
+ if (!c) { |
+ return Smi::FromInt(1); |
+ } |
+ pthread_mutex_t* m = MutexAddr(isolate, holder, moffset); |
+ if (!m) { |
+ return Smi::FromInt(1); |
+ } |
+ |
+ //printf("Cond wait %p %p\n", c, m); |
+ int err = pthread_cond_wait(c, m); |
+ //printf("Cond wait done.\n"); |
+ |
+ return Smi::FromInt(err); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferCondSignal) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 2); |
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); |
+ |
+ pthread_cond_t* c = CondAddr(isolate, holder, offset); |
+ if (!c) { |
+ return Smi::FromInt(1); |
+ } |
+ |
+ //printf("Cond signal %p\n", c); |
+ int err = pthread_cond_signal(c); |
+ //printf("Cond signal done.\n"); |
+ return Smi::FromInt(err); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferCondBroadcast) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 2); |
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); |
+ |
+ pthread_cond_t* c = CondAddr(isolate, holder, offset); |
+ if (!c) { |
+ return Smi::FromInt(1); |
+ } |
+ |
+ //printf("Cond broadcast %p\n", c); |
+ int err = pthread_cond_broadcast(c); |
+ //printf("Cond broadcast done.\n"); |
+ return Smi::FromInt(err); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferCondSize) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 1); |
+ return Smi::FromInt(COND_SIZE); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferBarrierInit) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 3); |
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, count, 2); |
+ |
+ pthread_barrier_t* b = BarrierAddr(isolate, holder, offset); |
+ if (!b) { |
+ return Smi::FromInt(1); |
+ } |
+ |
+ size_t c; |
+ if (!TryNumberToSize(isolate, *count, &c)) { |
+ return 0; |
+ } |
+ |
+ //printf("Barrier init %p\n", b); |
+ int err = pthread_barrier_init(b, NULL, c); |
+ //printf("Barrier init done.\n"); |
+ return Smi::FromInt(err); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferBarrierDestroy) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 2); |
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); |
+ |
+ pthread_barrier_t* b = BarrierAddr(isolate, holder, offset); |
+ if (!b) { |
+ return Smi::FromInt(1); |
+ } |
+ |
+ //printf("Barrier destroy %p\n", b); |
+ int err = pthread_barrier_destroy(b); |
+ //printf("Barrier destroy done.\n"); |
+ return Smi::FromInt(err); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferBarrierWait) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 2); |
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); |
+ |
+ pthread_barrier_t* b = BarrierAddr(isolate, holder, offset); |
+ if (!b) { |
+ return Smi::FromInt(1); |
+ } |
+ |
+ //printf("Barrier wait %p\n", b); |
+ int err = pthread_barrier_wait(b); |
+ //printf("Barrier wait done.\n"); |
+ |
+ return Smi::FromInt(err); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferBarrierSize) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 1); |
+ return Smi::FromInt(BARRIER_SIZE); |
+} |
+ |
RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferNeuter) { |
HandleScope scope(isolate); |