bool IsExternal() const;
/**
+ * Returns true if this ArrayBuffer may be neutered.
+ */
+ bool IsNeuterable() const;
+
+ /**
* Neuters this ArrayBuffer and all its views (typed arrays).
* Neutering sets the byte length of the buffer and all typed arrays to zero,
* preventing JavaScript from ever accessing underlying backing store.
- * ArrayBuffer should have been externalized.
+ * ArrayBuffer should have been externalized and must be neuterable.
*/
void Neuter();
}
+bool v8::ArrayBuffer::IsNeuterable() const {
+ return Utils::OpenHandle(this)->is_neuterable();
+}
+
+
v8::ArrayBuffer::Contents v8::ArrayBuffer::Externalize() {
i::Handle<i::JSArrayBuffer> obj = Utils::OpenHandle(this);
Utils::ApiCheck(!obj->is_external(),
Utils::ApiCheck(obj->is_external(),
"v8::ArrayBuffer::Neuter",
"Only externalized ArrayBuffers can be neutered");
+ Utils::ApiCheck(obj->is_neuterable(), "v8::ArrayBuffer::Neuter",
+ "Only neuterable ArrayBuffers can be neutered");
LOG_API(obj->GetIsolate(), "v8::ArrayBuffer::Neuter()");
ENTER_V8(isolate);
i::Runtime::NeuterArrayBuffer(obj);
}
+bool JSArrayBuffer::is_neuterable() {
+ return BooleanBit::get(flag(), kIsNeuterableBit);
+}
+
+
+void JSArrayBuffer::set_is_neuterable(bool value) {
+ set_flag(BooleanBit::set(flag(), kIsNeuterableBit, value));
+}
+
+
ACCESSORS(JSArrayBuffer, weak_next, Object, kWeakNextOffset)
ACCESSORS(JSArrayBuffer, weak_first_view, Object, kWeakFirstViewOffset)
void JSArrayBuffer::Neuter() {
- DCHECK(is_external());
+ CHECK(is_neuterable());
+ CHECK(is_external());
set_backing_store(NULL);
set_byte_length(Smi::FromInt(0));
}
void JSArrayBufferView::NeuterView() {
+ CHECK(JSArrayBuffer::cast(buffer())->is_neuterable());
set_byte_offset(Smi::FromInt(0));
set_byte_length(Smi::FromInt(0));
}
inline bool should_be_freed();
inline void set_should_be_freed(bool value);
+ inline bool is_neuterable();
+ inline void set_is_neuterable(bool value);
+
// [weak_next]: linked list of array buffers.
DECL_ACCESSORS(weak_next, Object)
// Bit position in a flag
static const int kIsExternalBit = 0;
static const int kShouldBeFreed = 1;
+ static const int kIsNeuterableBit = 2;
DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayBuffer);
};
array_buffer->set_backing_store(data);
array_buffer->set_flag(Smi::FromInt(0));
array_buffer->set_is_external(is_external);
+ array_buffer->set_is_neuterable(true);
Handle<Object> byte_length =
isolate->factory()->NewNumberFromSize(allocated_length);
}
+THREADED_TEST(ArrayBuffer_DisableNeuter) {
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope handle_scope(isolate);
+
+ i::ScopedVector<uint8_t> my_data(100);
+ memset(my_data.start(), 0, 100);
+ Local<v8::ArrayBuffer> ab =
+ v8::ArrayBuffer::New(isolate, my_data.start(), 100);
+ CHECK(ab->IsNeuterable());
+
+ i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
+ buf->set_is_neuterable(false);
+
+ CHECK(!ab->IsNeuterable());
+}
+
+
static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));