Change ArrayBuffer API and implementation to use embedder-provided allocator.
R=svenpanne@chromium.org Review URL: https://codereview.chromium.org/15855012 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15056 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
b90bd6987b
commit
9278a4b7b1
91
include/v8.h
91
include/v8.h
@ -2370,30 +2370,6 @@ class V8EXPORT Function : public Object {
|
||||
static void CheckCast(Value* obj);
|
||||
};
|
||||
|
||||
/**
|
||||
* The contents of an |ArrayBuffer|. Externalization of |ArrayBuffer|
|
||||
* populates an instance of this class with a pointer to data and byte length.
|
||||
*
|
||||
* |ArrayBufferContents| is the owner of its data. When an instance of
|
||||
* this class is destructed, the |Data| is freed.
|
||||
*
|
||||
* This API is experimental and may change significantly.
|
||||
*/
|
||||
class V8EXPORT ArrayBufferContents {
|
||||
public:
|
||||
ArrayBufferContents() : data_(NULL), byte_length_(0) {}
|
||||
~ArrayBufferContents();
|
||||
|
||||
void* Data() const { return data_; }
|
||||
size_t ByteLength() const { return byte_length_; }
|
||||
|
||||
private:
|
||||
void* data_;
|
||||
size_t byte_length_;
|
||||
|
||||
friend class ArrayBuffer;
|
||||
};
|
||||
|
||||
#ifndef V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT
|
||||
#define V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT 2
|
||||
#endif
|
||||
@ -2404,6 +2380,53 @@ class V8EXPORT ArrayBufferContents {
|
||||
*/
|
||||
class V8EXPORT ArrayBuffer : public Object {
|
||||
public:
|
||||
/**
|
||||
* Allocator that V8 uses to allocate |ArrayBuffer|'s memory.
|
||||
* The allocator is a global V8 setting. It should be set with
|
||||
* V8::SetArrayBufferAllocator prior to creation of a first ArrayBuffer.
|
||||
*
|
||||
* This API is experimental and may change significantly.
|
||||
*/
|
||||
class V8EXPORT Allocator { // NOLINT
|
||||
public:
|
||||
virtual ~Allocator() {}
|
||||
|
||||
/**
|
||||
* Allocate |length| bytes. Return NULL if allocation is not successful.
|
||||
*/
|
||||
virtual void* Allocate(size_t length) = 0;
|
||||
/**
|
||||
* Free the memory pointed to |data|. That memory is guaranteed to be
|
||||
* previously allocated by |Allocate|.
|
||||
*/
|
||||
virtual void Free(void* data) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* The contents of an |ArrayBuffer|. Externalization of |ArrayBuffer|
|
||||
* returns an instance of this class, populated, with a pointer to data
|
||||
* and byte length.
|
||||
*
|
||||
* The Data pointer of ArrayBuffer::Contents is always allocated with
|
||||
* Allocator::Allocate that is set with V8::SetArrayBufferAllocator.
|
||||
*
|
||||
* This API is experimental and may change significantly.
|
||||
*/
|
||||
class V8EXPORT 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 ArrayBuffer;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Data length in bytes.
|
||||
*/
|
||||
@ -2440,14 +2463,18 @@ class V8EXPORT ArrayBuffer : public Object {
|
||||
void Neuter();
|
||||
|
||||
/**
|
||||
* Pass the ownership of this ArrayBuffer's backing store to
|
||||
* a given ArrayBufferContents.
|
||||
* Make this ArrayBuffer external. The pointer to underlying memory block
|
||||
* and byte length are returned as |Contents| structure. After ArrayBuffer
|
||||
* 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|
|
||||
* that has been set with V8::SetArrayBufferAllocator.
|
||||
*/
|
||||
void Externalize(ArrayBufferContents* contents);
|
||||
Contents Externalize();
|
||||
|
||||
V8_INLINE(static ArrayBuffer* Cast(Value* obj));
|
||||
|
||||
|
||||
static const int kInternalFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT;
|
||||
|
||||
private:
|
||||
@ -4193,6 +4220,14 @@ class V8EXPORT V8 {
|
||||
static void SetAllowCodeGenerationFromStringsCallback(
|
||||
AllowCodeGenerationFromStringsCallback that);
|
||||
|
||||
/**
|
||||
* Set allocator to use for ArrayBuffer memory.
|
||||
* The allocator should be set only once. The allocator should be set
|
||||
* before any code tha uses ArrayBuffers is executed.
|
||||
* This allocator is used in all isolates.
|
||||
*/
|
||||
static void SetArrayBufferAllocator(ArrayBuffer::Allocator* allocator);
|
||||
|
||||
/**
|
||||
* Ignore out-of-memory exceptions.
|
||||
*
|
||||
|
27
src/api.cc
27
src/api.cc
@ -5160,6 +5160,15 @@ void v8::V8::SetJitCodeEventHandler(
|
||||
isolate->logger()->SetCodeEventHandler(options, event_handler);
|
||||
}
|
||||
|
||||
void v8::V8::SetArrayBufferAllocator(
|
||||
ArrayBuffer::Allocator* allocator) {
|
||||
if (!ApiCheck(i::V8::ArrayBufferAllocator() == NULL,
|
||||
"v8::V8::SetArrayBufferAllocator",
|
||||
"ArrayBufferAllocator might only be set once"))
|
||||
return;
|
||||
i::V8::SetArrayBufferAllocator(allocator);
|
||||
}
|
||||
|
||||
|
||||
bool v8::V8::Dispose() {
|
||||
i::Isolate* isolate = i::Isolate::Current();
|
||||
@ -6129,25 +6138,17 @@ bool v8::ArrayBuffer::IsExternal() const {
|
||||
return Utils::OpenHandle(this)->is_external();
|
||||
}
|
||||
|
||||
v8::ArrayBufferContents::~ArrayBufferContents() {
|
||||
free(data_);
|
||||
data_ = NULL;
|
||||
byte_length_ = 0;
|
||||
}
|
||||
|
||||
|
||||
void v8::ArrayBuffer::Externalize(ArrayBufferContents* contents) {
|
||||
v8::ArrayBuffer::Contents v8::ArrayBuffer::Externalize() {
|
||||
i::Handle<i::JSArrayBuffer> obj = Utils::OpenHandle(this);
|
||||
ApiCheck(!obj->is_external(),
|
||||
"v8::ArrayBuffer::Externalize",
|
||||
"ArrayBuffer already externalized");
|
||||
obj->set_is_external(true);
|
||||
size_t byte_length = static_cast<size_t>(obj->byte_length()->Number());
|
||||
ApiCheck(contents->data_ == NULL,
|
||||
"v8::ArrayBuffer::Externalize",
|
||||
"Externalizing into non-empty ArrayBufferContents");
|
||||
contents->data_ = obj->backing_store();
|
||||
contents->byte_length_ = byte_length;
|
||||
Contents contents;
|
||||
contents.data_ = obj->backing_store();
|
||||
contents.byte_length_ = byte_length;
|
||||
return contents;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1571,6 +1571,13 @@ static void EnableHarmonyTypedArraysViaCommandLine() {
|
||||
#endif
|
||||
|
||||
|
||||
class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
|
||||
public:
|
||||
virtual void* Allocate(size_t length) { return malloc(length); }
|
||||
virtual void Free(void* data) { free(data); }
|
||||
};
|
||||
|
||||
|
||||
int Shell::Main(int argc, char* argv[]) {
|
||||
if (!SetOptions(argc, argv)) return 1;
|
||||
#ifndef V8_SHARED
|
||||
@ -1579,6 +1586,8 @@ int Shell::Main(int argc, char* argv[]) {
|
||||
#else
|
||||
EnableHarmonyTypedArraysViaCommandLine();
|
||||
#endif
|
||||
ShellArrayBufferAllocator array_buffer_allocator;
|
||||
v8::V8::SetArrayBufferAllocator(&array_buffer_allocator);
|
||||
int result = 0;
|
||||
Isolate* isolate = Isolate::GetCurrent();
|
||||
DumbLineEditor dumb_line_editor(isolate);
|
||||
|
@ -663,7 +663,8 @@ static void ArrayBufferWeakCallback(v8::Isolate* external_isolate,
|
||||
isolate, array_buffer->byte_length());
|
||||
isolate->heap()->AdjustAmountOfExternalAllocatedMemory(
|
||||
-static_cast<intptr_t>(allocated_length));
|
||||
free(data);
|
||||
CHECK(V8::ArrayBufferAllocator() != NULL);
|
||||
V8::ArrayBufferAllocator()->Free(data);
|
||||
}
|
||||
object->Dispose(external_isolate);
|
||||
}
|
||||
@ -699,8 +700,9 @@ bool Runtime::SetupArrayBufferAllocatingData(
|
||||
Handle<JSArrayBuffer> array_buffer,
|
||||
size_t allocated_length) {
|
||||
void* data;
|
||||
CHECK(V8::ArrayBufferAllocator() != NULL);
|
||||
if (allocated_length != 0) {
|
||||
data = malloc(allocated_length);
|
||||
data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
|
||||
if (data == NULL) return false;
|
||||
memset(data, 0, allocated_length);
|
||||
} else {
|
||||
|
@ -56,6 +56,7 @@ bool V8::has_been_disposed_ = false;
|
||||
bool V8::has_fatal_error_ = false;
|
||||
bool V8::use_crankshaft_ = true;
|
||||
List<CallCompletedCallback>* V8::call_completed_callbacks_ = NULL;
|
||||
v8::ArrayBuffer::Allocator* V8::array_buffer_allocator_ = NULL;
|
||||
|
||||
static LazyMutex entropy_mutex = LAZY_MUTEX_INITIALIZER;
|
||||
|
||||
|
11
src/v8.h
11
src/v8.h
@ -121,6 +121,15 @@ class V8 : public AllStatic {
|
||||
static void RemoveCallCompletedCallback(CallCompletedCallback callback);
|
||||
static void FireCallCompletedCallback(Isolate* isolate);
|
||||
|
||||
static v8::ArrayBuffer::Allocator* ArrayBufferAllocator() {
|
||||
return array_buffer_allocator_;
|
||||
}
|
||||
|
||||
static void SetArrayBufferAllocator(v8::ArrayBuffer::Allocator *allocator) {
|
||||
CHECK_EQ(NULL, array_buffer_allocator_);
|
||||
array_buffer_allocator_ = allocator;
|
||||
}
|
||||
|
||||
private:
|
||||
static void InitializeOncePerProcessImpl();
|
||||
static void InitializeOncePerProcess();
|
||||
@ -139,6 +148,8 @@ class V8 : public AllStatic {
|
||||
static bool use_crankshaft_;
|
||||
// List of callbacks when a Call completes.
|
||||
static List<CallCompletedCallback>* call_completed_callbacks_;
|
||||
// Allocator for external array buffers.
|
||||
static v8::ArrayBuffer::Allocator* array_buffer_allocator_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -98,10 +98,21 @@ static void PrintTestList(CcTest* current) {
|
||||
v8::Isolate* CcTest::default_isolate_;
|
||||
|
||||
|
||||
class CcTestArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
|
||||
public:
|
||||
virtual void* Allocate(size_t length) { return malloc(length); }
|
||||
virtual void Free(void* data) { free(data); }
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
v8::internal::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
|
||||
v8::internal::FLAG_harmony_array_buffer = true;
|
||||
v8::internal::FLAG_harmony_typed_arrays = true;
|
||||
|
||||
CcTestArrayBufferAllocator array_buffer_allocator;
|
||||
v8::V8::SetArrayBufferAllocator(&array_buffer_allocator);
|
||||
|
||||
CcTest::set_default_isolate(v8::Isolate::GetCurrent());
|
||||
CHECK(CcTest::default_isolate() != NULL);
|
||||
int tests_run = 0;
|
||||
|
@ -2570,6 +2570,19 @@ THREADED_TEST(SymbolProperties) {
|
||||
}
|
||||
|
||||
|
||||
class ScopedArrayBufferContents {
|
||||
public:
|
||||
explicit ScopedArrayBufferContents(
|
||||
const v8::ArrayBuffer::Contents& contents)
|
||||
: contents_(contents) {}
|
||||
~ScopedArrayBufferContents() { free(contents_.Data()); }
|
||||
void* Data() const { return contents_.Data(); }
|
||||
size_t ByteLength() const { return contents_.ByteLength(); }
|
||||
private:
|
||||
const v8::ArrayBuffer::Contents contents_;
|
||||
};
|
||||
|
||||
|
||||
THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
|
||||
i::FLAG_harmony_array_buffer = true;
|
||||
i::FLAG_harmony_typed_arrays = true;
|
||||
@ -2583,8 +2596,7 @@ THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
|
||||
CHECK(!ab->IsExternal());
|
||||
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
|
||||
|
||||
v8::ArrayBufferContents ab_contents;
|
||||
ab->Externalize(&ab_contents);
|
||||
ScopedArrayBufferContents ab_contents(ab->Externalize());
|
||||
CHECK(ab->IsExternal());
|
||||
|
||||
CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
|
||||
@ -2626,8 +2638,7 @@ THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
|
||||
Local<v8::ArrayBuffer> ab1 = v8::ArrayBuffer::Cast(*result);
|
||||
CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
|
||||
CHECK(!ab1->IsExternal());
|
||||
v8::ArrayBufferContents ab1_contents;
|
||||
ab1->Externalize(&ab1_contents);
|
||||
ScopedArrayBufferContents ab1_contents(ab1->Externalize());
|
||||
CHECK(ab1->IsExternal());
|
||||
|
||||
result = CompileRun("ab1.byteLength");
|
||||
@ -2734,8 +2745,7 @@ THREADED_TEST(ArrayBuffer_NeuteringApi) {
|
||||
v8::Handle<v8::Float64Array> f64a =
|
||||
CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
|
||||
|
||||
v8::ArrayBufferContents contents;
|
||||
buffer->Externalize(&contents);
|
||||
ScopedArrayBufferContents contents(buffer->Externalize());
|
||||
buffer->Neuter();
|
||||
CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
|
||||
CheckIsNeutered(u8a);
|
||||
@ -2786,8 +2796,7 @@ THREADED_TEST(ArrayBuffer_NeuteringScript) {
|
||||
v8::Handle<v8::Float64Array> f64a(
|
||||
v8::Float64Array::Cast(*CompileRun("f64a")));
|
||||
|
||||
v8::ArrayBufferContents contents;
|
||||
ab->Externalize(&contents);
|
||||
ScopedArrayBufferContents contents(ab->Externalize());
|
||||
ab->Neuter();
|
||||
CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
|
||||
CheckIsNeutered(u8a);
|
||||
|
Loading…
Reference in New Issue
Block a user