};
+/**
+ * An instance of the built-in ArrayBuffer constructor (ES6 draft 15.13.5).
+ * This API is experimental and may change significantly.
+ */
+class V8EXPORT ArrayBuffer : public Object {
+ public:
+ /**
+ * Data length in bytes.
+ */
+ size_t ByteLength() const;
+ /**
+ * Raw pointer to the array buffer data
+ */
+ void* Data() const;
+
+ /**
+ * Create a new ArrayBuffer. Allocate |byte_length| bytes.
+ * Allocated memory will be owned by a created ArrayBuffer and
+ * will be deallocated when it is garbage-collected.
+ */
+ static Local<ArrayBuffer> New(size_t byte_length);
+
+ /**
+ * Create a new ArrayBuffer over an existing memory block.
+ * The memory block will not be reclaimed when a created ArrayBuffer
+ * is garbage-collected.
+ */
+ static Local<ArrayBuffer> New(void* data, size_t byte_length);
+
+ V8_INLINE(static ArrayBuffer* Cast(Value* obj));
+
+ private:
+ ArrayBuffer();
+ static void CheckCast(Value* obj);
+};
+
+
/**
* An instance of the built-in Date constructor (ECMA-262, 15.9).
*/
static const int kJSObjectHeaderSize = 3 * kApiPointerSize;
static const int kFixedArrayHeaderSize = 2 * kApiPointerSize;
static const int kContextHeaderSize = 2 * kApiPointerSize;
- static const int kContextEmbedderDataIndex = 55;
+ static const int kContextEmbedderDataIndex = 56;
static const int kFullStringRepresentationMask = 0x07;
static const int kStringEncodingMask = 0x4;
static const int kExternalTwoByteRepresentationTag = 0x02;
}
+ArrayBuffer* ArrayBuffer::Cast(v8::Value* value) {
+#ifdef V8_ENABLE_CHECKS
+ CheckCast(value);
+#endif
+ return static_cast<ArrayBuffer*>(value);
+}
+
+
Function* Function::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
CheckCast(value);
#include "profile-generator-inl.h"
#include "property-details.h"
#include "property.h"
+#include "runtime.h"
#include "runtime-profiler.h"
#include "scanner-character-streams.h"
#include "snapshot.h"
}
+void v8::ArrayBuffer::CheckCast(Value* that) {
+ if (IsDeadCheck(i::Isolate::Current(), "v8::ArrayBuffer::Cast()")) return;
+ i::Handle<i::Object> obj = Utils::OpenHandle(that);
+ ApiCheck(obj->IsJSArrayBuffer(),
+ "v8::ArrayBuffer::Cast()",
+ "Could not convert to ArrayBuffer");
+}
+
+
void v8::Date::CheckCast(v8::Value* that) {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::Date::Cast()")) return;
}
+size_t v8::ArrayBuffer::ByteLength() const {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::ArrayBuffer::ByteLength()")) return 0;
+ i::Handle<i::JSArrayBuffer> obj = Utils::OpenHandle(this);
+ return static_cast<size_t>(obj->byte_length()->Number());
+}
+
+
+void* v8::ArrayBuffer::Data() const {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::ArrayBuffer::Data()")) return 0;
+ i::Handle<i::JSArrayBuffer> obj = Utils::OpenHandle(this);
+ return obj->backing_store();
+}
+
+
+Local<ArrayBuffer> v8::ArrayBuffer::New(size_t byte_length) {
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::ArrayBuffer::New(size_t)");
+ LOG_API(isolate, "v8::ArrayBuffer::New(size_t)");
+ ENTER_V8(isolate);
+ i::Handle<i::JSArrayBuffer> obj =
+ isolate->factory()->NewJSArrayBuffer();
+ i::Runtime::SetupArrayBufferAllocatingData(isolate, obj, byte_length);
+ return Utils::ToLocal(obj);
+}
+
+
+Local<ArrayBuffer> v8::ArrayBuffer::New(void* data, size_t byte_length) {
+ i::Isolate* isolate = i::Isolate::Current();
+ EnsureInitializedForIsolate(isolate, "v8::ArrayBuffer::New(void*, size_t)");
+ LOG_API(isolate, "v8::ArrayBuffer::New(void*, size_t)");
+ ENTER_V8(isolate);
+ i::Handle<i::JSArrayBuffer> obj =
+ isolate->factory()->NewJSArrayBuffer();
+ i::Runtime::SetupArrayBuffer(isolate, obj, data, byte_length);
+ return Utils::ToLocal(obj);
+}
+
+
Local<Symbol> v8::Symbol::New(Isolate* isolate) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
EnsureInitializedForIsolate(i_isolate, "v8::Symbol::New()");
V(RegExp, JSRegExp) \
V(Object, JSObject) \
V(Array, JSArray) \
+ V(ArrayBuffer, JSArrayBuffer) \
V(String, String) \
V(Symbol, Symbol) \
V(Script, Object) \
v8::internal::Handle<v8::internal::JSObject> obj);
static inline Local<Array> ToLocal(
v8::internal::Handle<v8::internal::JSArray> obj);
+ static inline Local<ArrayBuffer> ToLocal(
+ v8::internal::Handle<v8::internal::JSArrayBuffer> obj);
static inline Local<Message> MessageToLocal(
v8::internal::Handle<v8::internal::Object> obj);
static inline Local<StackTrace> StackTraceToLocal(
MAKE_TO_LOCAL(ToLocal, JSRegExp, RegExp)
MAKE_TO_LOCAL(ToLocal, JSObject, Object)
MAKE_TO_LOCAL(ToLocal, JSArray, Array)
+MAKE_TO_LOCAL(ToLocal, JSArrayBuffer, ArrayBuffer)
MAKE_TO_LOCAL(ToLocal, FunctionTemplateInfo, FunctionTemplate)
MAKE_TO_LOCAL(ToLocal, ObjectTemplateInfo, ObjectTemplate)
MAKE_TO_LOCAL(ToLocal, SignatureInfo, Signature)
if (FLAG_harmony_typed_arrays) {
{ // -- A r r a y B u f f e r
- InstallFunction(global, "__ArrayBuffer", JS_ARRAY_BUFFER_TYPE,
- JSArrayBuffer::kSize,
- isolate()->initial_object_prototype(),
- Builtins::kIllegal, true);
+ Handle<JSFunction> array_buffer_fun =
+ InstallFunction(global, "__ArrayBuffer", JS_ARRAY_BUFFER_TYPE,
+ JSArrayBuffer::kSize,
+ isolate()->initial_object_prototype(),
+ Builtins::kIllegal, true);
+ native_context()->set_array_buffer_fun(*array_buffer_fun);
}
{
// -- T y p e d A r r a y s
V(GLOBAL_EVAL_FUN_INDEX, JSFunction, global_eval_fun) \
V(INSTANTIATE_FUN_INDEX, JSFunction, instantiate_fun) \
V(CONFIGURE_INSTANCE_FUN_INDEX, JSFunction, configure_instance_fun) \
+ V(ARRAY_BUFFER_FUN_INDEX, JSFunction, array_buffer_fun) \
V(FUNCTION_MAP_INDEX, Map, function_map) \
V(STRICT_MODE_FUNCTION_MAP_INDEX, Map, strict_mode_function_map) \
V(FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, function_without_prototype_map) \
GLOBAL_EVAL_FUN_INDEX,
INSTANTIATE_FUN_INDEX,
CONFIGURE_INSTANCE_FUN_INDEX,
+ ARRAY_BUFFER_FUN_INDEX,
MESSAGE_LISTENERS_INDEX,
MAKE_MESSAGE_FUN_INDEX,
GET_STACK_TRACE_LINE_INDEX,
}
+Handle<JSArrayBuffer> Factory::NewJSArrayBuffer() {
+ JSFunction* array_buffer_fun =
+ isolate()->context()->native_context()->array_buffer_fun();
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateJSObject(array_buffer_fun),
+ JSArrayBuffer);
+}
+
+
Handle<JSProxy> Factory::NewJSProxy(Handle<Object> handler,
Handle<Object> prototype) {
CALL_HEAP_FUNCTION(
uint32_t length,
EnsureElementsMode mode);
+ Handle<JSArrayBuffer> NewJSArrayBuffer();
+
Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object> prototype);
// Change the type of the argument into a JS object/function and reinitialize.
// Please note this does not perform a garbage collection.
MUST_USE_RESULT MaybeObject* AllocateFunctionPrototype(JSFunction* function);
+ // Allocates a JS ArrayBuffer object.
+ // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
+ // failed.
+ // Please note this does not perform a garbage collection.
+ MUST_USE_RESULT MaybeObject* AllocateJSArrayBuffer();
+
// Allocates a Harmony proxy or function proxy.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
}
+bool Runtime::SetupArrayBuffer(Isolate* isolate,
+ Handle<JSArrayBuffer> array_buffer,
+ void* data,
+ size_t allocated_length) {
+ array_buffer->set_backing_store(data);
+
+ Handle<Object> byte_length =
+ isolate->factory()->NewNumber(static_cast<double>(allocated_length));
+ CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
+ array_buffer->set_byte_length(*byte_length);
+ return true;
+}
+
+
+bool Runtime::SetupArrayBufferAllocatingData(
+ Isolate* isolate,
+ Handle<JSArrayBuffer> array_buffer,
+ size_t allocated_length) {
+ void* data;
+ if (allocated_length != 0) {
+ data = malloc(allocated_length);
+ if (data == NULL) return false;
+ memset(data, 0, allocated_length);
+ } else {
+ data = NULL;
+ }
+
+ if (!SetupArrayBuffer(isolate, array_buffer, data, allocated_length))
+ return false;
+
+ v8::Isolate* external_isolate = reinterpret_cast<v8::Isolate*>(isolate);
+ v8::Persistent<v8::Value> weak_handle = v8::Persistent<v8::Value>::New(
+ external_isolate, v8::Utils::ToLocal(Handle<Object>::cast(array_buffer)));
+ weak_handle.MakeWeak(external_isolate, data, ArrayBufferWeakCallback);
+ weak_handle.MarkIndependent(external_isolate);
+ isolate->heap()->AdjustAmountOfExternalAllocatedMemory(allocated_length);
+
+ return true;
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferInitialize) {
HandleScope scope(isolate);
ASSERT(args.length() == 2);
allocated_length = static_cast<size_t>(value);
}
- void* data;
- if (allocated_length != 0) {
- data = malloc(allocated_length);
-
- if (data == NULL) {
+ if (!Runtime::SetupArrayBufferAllocatingData(isolate,
+ holder, allocated_length)) {
return isolate->Throw(*isolate->factory()->
NewRangeError("invalid_array_buffer_length",
HandleVector<Object>(NULL, 0)));
- }
-
- memset(data, 0, allocated_length);
- } else {
- data = NULL;
- }
- holder->set_backing_store(data);
-
- Object* byte_length;
- {
- MaybeObject* maybe_byte_length =
- isolate->heap()->NumberFromDouble(
- static_cast<double>(allocated_length));
- if (!maybe_byte_length->ToObject(&byte_length)) return maybe_byte_length;
}
- CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
- holder->set_byte_length(byte_length);
-
- v8::Isolate* external_isolate = reinterpret_cast<v8::Isolate*>(isolate);
- v8::Persistent<v8::Value> weak_handle = v8::Persistent<v8::Value>::New(
- external_isolate, v8::Utils::ToLocal(Handle<Object>::cast(holder)));
- weak_handle.MakeWeak(external_isolate, data, ArrayBufferWeakCallback);
- weak_handle.MarkIndependent(external_isolate);
- isolate->heap()->AdjustAmountOfExternalAllocatedMemory(allocated_length);
return *holder;
}
Handle<Object> object,
Handle<Object> key);
+ static bool SetupArrayBuffer(Isolate* isolate,
+ Handle<JSArrayBuffer> array_buffer,
+ void* data,
+ size_t allocated_length);
+
+ static bool SetupArrayBufferAllocatingData(
+ Isolate* isolate,
+ Handle<JSArrayBuffer> array_buffer,
+ size_t allocated_length);
+
// Helper functions used stubs.
static void PerformGC(Object* result);
}
+THREADED_TEST(ArrayBuffer) {
+ i::FLAG_harmony_typed_arrays = true;
+
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope handle_scope(isolate);
+
+ Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(1024);
+ HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
+
+ CHECK_EQ(1024, ab->ByteLength());
+ uint8_t* data = static_cast<uint8_t*>(ab->Data());
+ ASSERT(data != NULL);
+ env->Global()->Set(v8_str("ab"), ab);
+
+ v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
+ CHECK_EQ(1024, result->Int32Value());
+
+ result = CompileRun("var u8 = new __Uint8Array(ab);"
+ "u8[0] = 0xFF;"
+ "u8[1] = 0xAA;"
+ "u8.length");
+ CHECK_EQ(1024, result->Int32Value());
+ CHECK_EQ(0xFF, data[0]);
+ CHECK_EQ(0xAA, data[1]);
+ data[0] = 0xCC;
+ data[1] = 0x11;
+ result = CompileRun("u8[0] + u8[1]");
+ CHECK_EQ(0xDD, result->Int32Value());
+
+ result = CompileRun("var ab1 = new __ArrayBuffer(2);"
+ "var u8_a = new __Uint8Array(ab1);"
+ "u8_a[0] = 0xAA;"
+ "u8_a[1] = 0xFF; u8_a.buffer");
+ Local<v8::ArrayBuffer> ab1 = v8::ArrayBuffer::Cast(*result);
+ CHECK_EQ(2, ab1->ByteLength());
+ uint8_t* ab1_data = static_cast<uint8_t*>(ab1->Data());
+ CHECK_EQ(0xAA, ab1_data[0]);
+ CHECK_EQ(0xFF, ab1_data[1]);
+ ab1_data[0] = 0xCC;
+ ab1_data[1] = 0x11;
+ result = CompileRun("u8_a[0] + u8_a[1]");
+ CHECK_EQ(0xDD, result->Int32Value());
+
+ uint8_t* my_data = new uint8_t[100];
+ memset(my_data, 0, 100);
+ Local<v8::ArrayBuffer> ab3 = v8::ArrayBuffer::New(my_data, 100);
+ CHECK_EQ(100, ab3->ByteLength());
+ CHECK_EQ(my_data, ab3->Data());
+ env->Global()->Set(v8_str("ab3"), ab3);
+ result = CompileRun("var u8_b = new __Uint8Array(ab3);"
+ "u8_b[0] = 0xBB;"
+ "u8_b[1] = 0xCC;"
+ "u8_b.length");
+ CHECK_EQ(100, result->Int32Value());
+ CHECK_EQ(0xBB, my_data[0]);
+ CHECK_EQ(0xCC, my_data[1]);
+ my_data[0] = 0xCC;
+ my_data[1] = 0x11;
+ result = CompileRun("u8_b[0] + u8_b[1]");
+ CHECK_EQ(0xDD, result->Int32Value());
+
+
+ delete[] my_data;
+}
+
+
THREADED_TEST(HiddenProperties) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());