| 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);
 | 
| 
 |