Skip to content

Commit

Permalink
Implement SharedArrayBuffer.
Browse files Browse the repository at this point in the history
This adds a new external type (v8::SharedArrayBuffer) that uses a JSArrayBuffer under the hood. It can be distinguished from an ArrayBuffer by the newly-added is_shared() bit.

Currently there is no difference in functionality between a SharedArrayBuffer and an ArrayBuffer. However, a future CL will add the Atomics API, which is only available on an SharedArrayBuffer. All non-atomic accesses are identical to ArrayBuffer accesses.

BUG=

Review URL: https://codereview.chromium.org/1136553006

Cr-Commit-Position: refs/heads/master@{#28588}
  • Loading branch information
binji authored and Commit bot committed May 22, 2015
1 parent 871ab7f commit 57170bf
Show file tree
Hide file tree
Showing 20 changed files with 1,045 additions and 30 deletions.
3 changes: 2 additions & 1 deletion BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,8 @@ action("js2c_experimental") {
"src/harmony-regexp.js",
"src/harmony-reflect.js",
"src/harmony-spread.js",
"src/harmony-object.js"
"src/harmony-object.js",
"src/harmony-sharedarraybuffer.js"
]

outputs = [
Expand Down
116 changes: 115 additions & 1 deletion include/v8.h
Original file line number Diff line number Diff line change
Expand Up @@ -1920,6 +1920,13 @@ class V8_EXPORT Value : public Data {
*/
bool IsDataView() const;

/**
* Returns true if this value is a SharedArrayBuffer.
* This is an experimental feature.
*/
bool IsSharedArrayBuffer() const;


V8_WARN_UNUSED_RESULT MaybeLocal<Boolean> ToBoolean(
Local<Context> context) const;
V8_WARN_UNUSED_RESULT MaybeLocal<Number> ToNumber(
Expand Down Expand Up @@ -3344,7 +3351,7 @@ class V8_EXPORT ArrayBuffer : public Object {
ArrayBufferCreationMode mode = ArrayBufferCreationMode::kExternalized);

/**
* Returns true if ArrayBuffer is extrenalized, that is, does not
* Returns true if ArrayBuffer is externalized, that is, does not
* own its memory block.
*/
bool IsExternal() const;
Expand Down Expand Up @@ -3630,6 +3637,105 @@ class V8_EXPORT DataView : public ArrayBufferView {
};


/**
* An instance of the built-in SharedArrayBuffer constructor.
* This API is experimental and may change significantly.
*/
class V8_EXPORT SharedArrayBuffer : public Object {
public:
/**
* The contents of an |SharedArrayBuffer|. Externalization of
* |SharedArrayBuffer| returns an instance of this class, populated, with a
* pointer to data and byte length.
*
* The Data pointer of SharedArrayBuffer::Contents is always allocated with
* |ArrayBuffer::Allocator::Allocate| by the allocator specified in
* v8::Isolate::CreateParams::array_buffer_allocator.
*
* This API is experimental and may change significantly.
*/
class V8_EXPORT Contents { // NOLINT
public:
Contents() : data_(NULL), byte_length_(0) {}

void* Data() const { return data_; }
size_t ByteLength() const { return byte_length_; }

private:
void* data_;
size_t byte_length_;

friend class SharedArrayBuffer;
};


/**
* Data length in bytes.
*/
size_t ByteLength() const;

/**
* Create a new SharedArrayBuffer. Allocate |byte_length| bytes.
* Allocated memory will be owned by a created SharedArrayBuffer and
* will be deallocated when it is garbage-collected,
* unless the object is externalized.
*/
static Local<SharedArrayBuffer> New(Isolate* isolate, size_t byte_length);

/**
* Create a new SharedArrayBuffer over an existing memory block. The created
* array buffer is immediately in externalized state unless otherwise
* specified. The memory block will not be reclaimed when a created
* SharedArrayBuffer is garbage-collected.
*/
static Local<SharedArrayBuffer> New(
Isolate* isolate, void* data, size_t byte_length,
ArrayBufferCreationMode mode = ArrayBufferCreationMode::kExternalized);

/**
* Returns true if SharedArrayBuffer is externalized, that is, does not
* own its memory block.
*/
bool IsExternal() const;

/**
* Make this SharedArrayBuffer external. The pointer to underlying memory
* block and byte length are returned as |Contents| structure. After
* SharedArrayBuffer had been etxrenalized, it does no longer owns the memory
* block. The caller should take steps to free memory when it is no longer
* needed.
*
* The memory block is guaranteed to be allocated with |Allocator::Allocate|
* by the allocator specified in
* v8::Isolate::CreateParams::array_buffer_allocator.
*
*/
Contents Externalize();

/**
* Get a pointer to the ArrayBuffer's underlying memory block without
* externalizing it. If the ArrayBuffer is not externalized, this pointer
* will become invalid as soon as the ArrayBuffer became garbage collected.
*
* The embedder should make sure to hold a strong reference to the
* ArrayBuffer while accessing this pointer.
*
* The memory block is guaranteed to be allocated with |Allocator::Allocate|
* by the allocator specified in
* v8::Isolate::CreateParams::array_buffer_allocator.
*/
Contents GetContents();

V8_INLINE static SharedArrayBuffer* Cast(Value* obj);

static const int kInternalFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT;

private:
SharedArrayBuffer();
static void CheckCast(Value* obj);
};


/**
* An instance of the built-in Date constructor (ECMA-262, 15.9).
*/
Expand Down Expand Up @@ -7817,6 +7923,14 @@ DataView* DataView::Cast(v8::Value* value) {
}


SharedArrayBuffer* SharedArrayBuffer::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
CheckCast(value);
#endif
return static_cast<SharedArrayBuffer*>(value);
}


Function* Function::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
CheckCast(value);
Expand Down
89 changes: 83 additions & 6 deletions src/api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2679,7 +2679,8 @@ bool Value::IsArray() const {


bool Value::IsArrayBuffer() const {
return Utils::OpenHandle(this)->IsJSArrayBuffer();
i::Handle<i::Object> obj = Utils::OpenHandle(this);
return obj->IsJSArrayBuffer() && !i::JSArrayBuffer::cast(*obj)->is_shared();
}


Expand All @@ -2700,6 +2701,7 @@ bool Value::IsTypedArray() const {
i::JSTypedArray::cast(*obj)->type() == i::kExternal##Type##Array; \
}


TYPED_ARRAYS(VALUE_IS_TYPED_ARRAY)

#undef VALUE_IS_TYPED_ARRAY
Expand All @@ -2710,6 +2712,12 @@ bool Value::IsDataView() const {
}


bool Value::IsSharedArrayBuffer() const {
i::Handle<i::Object> obj = Utils::OpenHandle(this);
return obj->IsJSArrayBuffer() && i::JSArrayBuffer::cast(*obj)->is_shared();
}


bool Value::IsObject() const {
return Utils::OpenHandle(this)->IsJSObject();
}
Expand Down Expand Up @@ -3086,9 +3094,9 @@ void v8::Promise::Resolver::CheckCast(Value* that) {

void v8::ArrayBuffer::CheckCast(Value* that) {
i::Handle<i::Object> obj = Utils::OpenHandle(that);
Utils::ApiCheck(obj->IsJSArrayBuffer(),
"v8::ArrayBuffer::Cast()",
"Could not convert to ArrayBuffer");
Utils::ApiCheck(
obj->IsJSArrayBuffer() && !i::JSArrayBuffer::cast(*obj)->is_shared(),
"v8::ArrayBuffer::Cast()", "Could not convert to ArrayBuffer");
}


Expand Down Expand Up @@ -3131,6 +3139,15 @@ void v8::DataView::CheckCast(Value* that) {
}


void v8::SharedArrayBuffer::CheckCast(Value* that) {
i::Handle<i::Object> obj = Utils::OpenHandle(that);
Utils::ApiCheck(
obj->IsJSArrayBuffer() && i::JSArrayBuffer::cast(*obj)->is_shared(),
"v8::SharedArrayBuffer::Cast()",
"Could not convert to SharedArrayBuffer");
}


void v8::Date::CheckCast(v8::Value* that) {
i::Handle<i::Object> obj = Utils::OpenHandle(that);
i::Isolate* isolate = NULL;
Expand Down Expand Up @@ -6305,7 +6322,7 @@ Local<ArrayBuffer> v8::ArrayBuffer::New(Isolate* isolate, size_t byte_length) {
LOG_API(i_isolate, "v8::ArrayBuffer::New(size_t)");
ENTER_V8(i_isolate);
i::Handle<i::JSArrayBuffer> obj =
i_isolate->factory()->NewJSArrayBuffer();
i_isolate->factory()->NewJSArrayBuffer(i::SharedFlag::kNotShared);
i::Runtime::SetupArrayBufferAllocatingData(i_isolate, obj, byte_length);
return Utils::ToLocal(obj);
}
Expand All @@ -6318,7 +6335,7 @@ Local<ArrayBuffer> v8::ArrayBuffer::New(Isolate* isolate, void* data,
LOG_API(i_isolate, "v8::ArrayBuffer::New(void*, size_t)");
ENTER_V8(i_isolate);
i::Handle<i::JSArrayBuffer> obj =
i_isolate->factory()->NewJSArrayBuffer();
i_isolate->factory()->NewJSArrayBuffer(i::SharedFlag::kNotShared);
i::Runtime::SetupArrayBuffer(i_isolate, obj,
mode == ArrayBufferCreationMode::kExternalized,
data, byte_length);
Expand Down Expand Up @@ -6424,6 +6441,66 @@ Local<DataView> DataView::New(Handle<ArrayBuffer> array_buffer,
}


bool v8::SharedArrayBuffer::IsExternal() const {
return Utils::OpenHandle(this)->is_external();
}


v8::SharedArrayBuffer::Contents v8::SharedArrayBuffer::Externalize() {
i::Handle<i::JSArrayBuffer> self = Utils::OpenHandle(this);
i::Isolate* isolate = self->GetIsolate();
Utils::ApiCheck(!self->is_external(), "v8::SharedArrayBuffer::Externalize",
"SharedArrayBuffer already externalized");
self->set_is_external(true);
isolate->heap()->UnregisterArrayBuffer(self->backing_store());
return GetContents();
}


v8::SharedArrayBuffer::Contents v8::SharedArrayBuffer::GetContents() {
i::Handle<i::JSArrayBuffer> self = Utils::OpenHandle(this);
size_t byte_length = static_cast<size_t>(self->byte_length()->Number());
Contents contents;
contents.data_ = self->backing_store();
contents.byte_length_ = byte_length;
return contents;
}


size_t v8::SharedArrayBuffer::ByteLength() const {
i::Handle<i::JSArrayBuffer> obj = Utils::OpenHandle(this);
return static_cast<size_t>(obj->byte_length()->Number());
}


Local<SharedArrayBuffer> v8::SharedArrayBuffer::New(Isolate* isolate,
size_t byte_length) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
LOG_API(i_isolate, "v8::SharedArrayBuffer::New(size_t)");
ENTER_V8(i_isolate);
i::Handle<i::JSArrayBuffer> obj =
i_isolate->factory()->NewJSArrayBuffer(i::SharedFlag::kShared);
i::Runtime::SetupArrayBufferAllocatingData(i_isolate, obj, byte_length, true,
i::SharedFlag::kShared);
return Utils::ToLocalShared(obj);
}


Local<SharedArrayBuffer> v8::SharedArrayBuffer::New(
Isolate* isolate, void* data, size_t byte_length,
ArrayBufferCreationMode mode) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
LOG_API(i_isolate, "v8::SharedArrayBuffer::New(void*, size_t)");
ENTER_V8(i_isolate);
i::Handle<i::JSArrayBuffer> obj =
i_isolate->factory()->NewJSArrayBuffer(i::SharedFlag::kShared);
i::Runtime::SetupArrayBuffer(i_isolate, obj,
mode == ArrayBufferCreationMode::kExternalized,
data, byte_length, i::SharedFlag::kShared);
return Utils::ToLocalShared(obj);
}


Local<Symbol> v8::Symbol::New(Isolate* isolate, Local<String> name) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
LOG_API(i_isolate, "Symbol::New()");
Expand Down
5 changes: 5 additions & 0 deletions src/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ class RegisteredExtension {
V(Float32Array, JSTypedArray) \
V(Float64Array, JSTypedArray) \
V(DataView, JSDataView) \
V(SharedArrayBuffer, JSArrayBuffer) \
V(Name, Name) \
V(String, String) \
V(Symbol, Symbol) \
Expand Down Expand Up @@ -230,6 +231,9 @@ class Utils {
static inline Local<Float64Array> ToLocalFloat64Array(
v8::internal::Handle<v8::internal::JSTypedArray> obj);

static inline Local<SharedArrayBuffer> ToLocalShared(
v8::internal::Handle<v8::internal::JSArrayBuffer> obj);

static inline Local<Message> MessageToLocal(
v8::internal::Handle<v8::internal::Object> obj);
static inline Local<Promise> PromiseToLocal(
Expand Down Expand Up @@ -360,6 +364,7 @@ MAKE_TO_LOCAL(ToLocal, JSArrayBuffer, ArrayBuffer)
MAKE_TO_LOCAL(ToLocal, JSArrayBufferView, ArrayBufferView)
MAKE_TO_LOCAL(ToLocal, JSDataView, DataView)
MAKE_TO_LOCAL(ToLocal, JSTypedArray, TypedArray)
MAKE_TO_LOCAL(ToLocalShared, JSArrayBuffer, SharedArrayBuffer)

TYPED_ARRAYS(MAKE_TO_LOCAL_TYPED_ARRAY)

Expand Down
2 changes: 1 addition & 1 deletion src/arraybuffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ utils.Import(function(from) {
function ArrayBufferConstructor(length) { // length = 1
if (%_IsConstructCall()) {
var byteLength = $toPositiveInteger(length, kInvalidArrayBufferLength);
%ArrayBufferInitialize(this, byteLength);
%ArrayBufferInitialize(this, byteLength, kNotShared);
} else {
throw MakeTypeError(kConstructorNotFunction, "ArrayBuffer");
}
Expand Down
17 changes: 17 additions & 0 deletions src/bootstrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1753,6 +1753,7 @@ EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_spreadcalls)
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_destructuring)
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_object)
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_spread_arrays)
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_sharedarraybuffer)


void Genesis::InstallNativeFunctions_harmony_proxies() {
Expand Down Expand Up @@ -1846,6 +1847,20 @@ void Genesis::InitializeGlobal_harmony_tostring() {
}


void Genesis::InitializeGlobal_harmony_sharedarraybuffer() {
if (!FLAG_harmony_sharedarraybuffer) return;

Handle<JSGlobalObject> global(
JSGlobalObject::cast(native_context()->global_object()));

Handle<JSFunction> shared_array_buffer_fun = InstallFunction(
global, "SharedArrayBuffer", JS_ARRAY_BUFFER_TYPE,
JSArrayBuffer::kSizeWithInternalFields,
isolate()->initial_object_prototype(), Builtins::kIllegal);
native_context()->set_shared_array_buffer_fun(*shared_array_buffer_fun);
}


Handle<JSFunction> Genesis::InstallInternalArray(Handle<JSObject> target,
const char* name,
ElementsKind elements_kind) {
Expand Down Expand Up @@ -2410,6 +2425,8 @@ bool Genesis::InstallExperimentalNatives() {
static const char* harmony_object_natives[] = {"native harmony-object.js",
NULL};
static const char* harmony_spread_arrays_natives[] = {nullptr};
static const char* harmony_sharedarraybuffer_natives[] = {
"native harmony-sharedarraybuffer.js", NULL};

for (int i = ExperimentalNatives::GetDebuggerCount();
i < ExperimentalNatives::GetBuiltinsCount(); i++) {
Expand Down
2 changes: 2 additions & 0 deletions src/contexts.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ enum BindingFlags {
V(TO_LENGTH_FUN_INDEX, JSFunction, to_length_fun) \
V(GLOBAL_EVAL_FUN_INDEX, JSFunction, global_eval_fun) \
V(ARRAY_BUFFER_FUN_INDEX, JSFunction, array_buffer_fun) \
V(SHARED_ARRAY_BUFFER_FUN_INDEX, JSFunction, shared_array_buffer_fun) \
V(ARRAY_BUFFER_MAP_INDEX, Map, array_buffer_map) \
V(UINT8_ARRAY_FUN_INDEX, JSFunction, uint8_array_fun) \
V(INT8_ARRAY_FUN_INDEX, JSFunction, int8_array_fun) \
Expand Down Expand Up @@ -381,6 +382,7 @@ class Context: public FixedArray {
FLOAT64_ARRAY_EXTERNAL_MAP_INDEX,
UINT8_CLAMPED_ARRAY_EXTERNAL_MAP_INDEX,
DATA_VIEW_FUN_INDEX,
SHARED_ARRAY_BUFFER_FUN_INDEX,
MESSAGE_LISTENERS_INDEX,
MAKE_MESSAGE_FUN_INDEX,
GET_STACK_TRACE_LINE_INDEX,
Expand Down
Loading

0 comments on commit 57170bf

Please sign in to comment.