aboutsummaryrefslogtreecommitdiff
path: root/src/node_buffer.cc
diff options
context:
space:
mode:
authorTrevor Norris <trev.norris@gmail.com>2015-05-26 12:42:14 -0600
committerRod Vagg <rod@vagg.org>2015-08-04 11:56:10 -0700
commit63da0dfd3a4460e117240e84b57af2137469497e (patch)
tree4806693f7d89ba36ebbe4ff1ab5f34e1b3cf90ea /src/node_buffer.cc
parent23be6ca189e1ebad24a814ed1c8c1c241fee354e (diff)
downloadandroid-node-v8-63da0dfd3a4460e117240e84b57af2137469497e.tar.gz
android-node-v8-63da0dfd3a4460e117240e84b57af2137469497e.tar.bz2
android-node-v8-63da0dfd3a4460e117240e84b57af2137469497e.zip
buffer: implement Uint8Array backed Buffer
With V8 4.4 removing the external array data API currently used by Buffer, the new implementation uses the Uint8Array to back Buffer. Buffers now have a maximum size of Smi::kMaxLength, as defined by V8. Which is ~2 GB on 64 bit and ~1 GB on 32 bit. The flag --use-old-buffer allows using the old Buffer implementation. This flag will be removed once V8 4.4 has landed. The two JS Buffer implementations have been split into two files for simplicity. Use getter to return expected .parent/.offset values for backwards compatibility. PR-URL: https://github.com/nodejs/io.js/pull/1825 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'src/node_buffer.cc')
-rw-r--r--src/node_buffer.cc395
1 files changed, 321 insertions, 74 deletions
diff --git a/src/node_buffer.cc b/src/node_buffer.cc
index 3f429817e1..d3398075d0 100644
--- a/src/node_buffer.cc
+++ b/src/node_buffer.cc
@@ -5,6 +5,8 @@
#include "env-inl.h"
#include "smalloc.h"
#include "string_bytes.h"
+#include "util.h"
+#include "util-inl.h"
#include "v8-profiler.h"
#include "v8.h"
@@ -28,6 +30,16 @@
size_t name##_length; \
char* name##_data;
+#define SPREAD_ARG(val, name) \
+ CHECK((val)->IsUint8Array()); \
+ Local<Uint8Array> name = (val).As<Uint8Array>(); \
+ ArrayBuffer::Contents name##_c = name->Buffer()->GetContents(); \
+ size_t name##_offset = name->ByteOffset(); \
+ name##_length = name->ByteLength(); \
+ name##_data = static_cast<char*>(name##_c.Data()) + name##_offset; \
+ if (name##_length > 0) \
+ CHECK_NE(name##_data, nullptr);
+
#define ARGS_THIS(argT, name) \
Local<Object> name = argT; \
name##_length = name->GetIndexedPropertiesExternalArrayDataLength(); \
@@ -48,6 +60,8 @@
namespace node {
namespace Buffer {
+using v8::ArrayBuffer;
+using v8::ArrayBufferCreationMode;
using v8::Context;
using v8::EscapableHandleScope;
using v8::Function;
@@ -61,6 +75,7 @@ using v8::Number;
using v8::Object;
using v8::String;
using v8::Uint32;
+using v8::Uint8Array;
using v8::Value;
@@ -70,10 +85,19 @@ bool HasInstance(Handle<Value> val) {
bool HasInstance(Handle<Object> obj) {
- if (!obj->HasIndexedPropertiesInExternalArrayData())
+ if (using_old_buffer) {
+ if (!obj->HasIndexedPropertiesInExternalArrayData())
+ return false;
+ v8::ExternalArrayType type =
+ obj->GetIndexedPropertiesExternalArrayDataType();
+ return type == v8::kExternalUint8Array;
+ }
+
+ if (!obj->IsUint8Array())
return false;
- v8::ExternalArrayType type = obj->GetIndexedPropertiesExternalArrayDataType();
- return type == v8::kExternalUint8Array;
+ Local<Uint8Array> array = obj.As<Uint8Array>();
+ Environment* env = Environment::GetCurrent(array->GetIsolate());
+ return array->GetPrototype()->StrictEquals(env->buffer_prototype_object());
}
@@ -86,8 +110,15 @@ char* Data(Handle<Value> val) {
char* Data(Handle<Object> obj) {
- CHECK(obj->HasIndexedPropertiesInExternalArrayData());
- return static_cast<char*>(obj->GetIndexedPropertiesExternalArrayData());
+ if (using_old_buffer) {
+ CHECK(obj->HasIndexedPropertiesInExternalArrayData());
+ return static_cast<char*>(obj->GetIndexedPropertiesExternalArrayData());
+ }
+
+ CHECK(obj->IsUint8Array());
+ Local<Uint8Array> ui = obj.As<Uint8Array>();
+ ArrayBuffer::Contents ab_c = ui->Buffer()->GetContents();
+ return static_cast<char*>(ab_c.Data()) + ui->ByteOffset();
}
@@ -98,8 +129,14 @@ size_t Length(Handle<Value> val) {
size_t Length(Handle<Object> obj) {
- CHECK(obj->HasIndexedPropertiesInExternalArrayData());
- return obj->GetIndexedPropertiesExternalArrayDataLength();
+ if (using_old_buffer) {
+ CHECK(obj->HasIndexedPropertiesInExternalArrayData());
+ return obj->GetIndexedPropertiesExternalArrayDataLength();
+ }
+
+ CHECK(obj->IsUint8Array());
+ Local<Uint8Array> ui = obj.As<Uint8Array>();
+ return ui->ByteLength();
}
@@ -107,11 +144,20 @@ Local<Object> New(Isolate* isolate, Handle<String> string, enum encoding enc) {
EscapableHandleScope scope(isolate);
size_t length = StringBytes::Size(isolate, string, enc);
+ char* data = static_cast<char*>(malloc(length));
- Local<Object> buf = New(isolate, length);
- char* data = Buffer::Data(buf);
- StringBytes::Write(isolate, data, length, string, enc);
+ if (data == nullptr)
+ return Local<Object>();
+ size_t actual = StringBytes::Write(isolate, data, length, string, enc);
+ CHECK(actual <= length);
+
+ if (actual < length) {
+ data = static_cast<char*>(realloc(data, actual));
+ CHECK_NE(data, nullptr);
+ }
+
+ Local<Object> buf = Use(isolate, data, actual);
return scope.Escape(buf);
}
@@ -123,19 +169,44 @@ Local<Object> New(Isolate* isolate, size_t length) {
}
-// TODO(trevnorris): these have a flaw by needing to call the Buffer inst then
-// Alloc. continue to look for a better architecture.
Local<Object> New(Environment* env, size_t length) {
EscapableHandleScope scope(env->isolate());
- CHECK_LE(length, kMaxLength);
+ if (using_old_buffer) {
+ CHECK_LE(length, kMaxLength);
- Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
- Local<Object> obj = env->buffer_constructor_function()->NewInstance(1, &arg);
+ Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
+ Local<Object> obj =
+ env->buffer_constructor_function()->NewInstance(1, &arg);
- smalloc::Alloc(env, obj, length);
+ smalloc::Alloc(env, obj, length);
- return scope.Escape(obj);
+ return scope.Escape(obj);
+ }
+
+ // V8 currently only allows a maximum Typed Array index of max Smi.
+ if (!IsValidSmi(length)) {
+ return Local<Object>();
+ }
+
+ void* data;
+ if (length > 0) {
+ data = malloc(length);
+ // NOTE: API change. Must check .IsEmpty() on the return object to see if
+ // the data was able to be allocated.
+ if (data == nullptr)
+ return Local<Object>();
+ } else {
+ data = nullptr;
+ }
+ Local<ArrayBuffer> ab =
+ ArrayBuffer::New(env->isolate(),
+ data,
+ length,
+ ArrayBufferCreationMode::kInternalized);
+ Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
+ ui->SetPrototype(env->buffer_prototype_object());
+ return scope.Escape(ui);
}
@@ -147,33 +218,59 @@ Local<Object> New(Isolate* isolate, const char* data, size_t length) {
}
-// TODO(trevnorris): for backwards compatibility this is left to copy the data,
-// but for consistency w/ the other should use data. And a copy version renamed
-// to something else.
+// Make a copy of "data". Why this isn't called "Copy", we'll never know.
Local<Object> New(Environment* env, const char* data, size_t length) {
EscapableHandleScope scope(env->isolate());
- CHECK_LE(length, kMaxLength);
+ if (using_old_buffer) {
+ CHECK_LE(length, kMaxLength);
+
+ Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
+ Local<Object> obj =
+ env->buffer_constructor_function()->NewInstance(1, &arg);
+
+ char* new_data;
+ if (length > 0) {
+ new_data = static_cast<char*>(malloc(length));
+ if (new_data == nullptr)
+ FatalError("node::Buffer::New(const char*, size_t)", "Out Of Memory");
+ memcpy(new_data, data, length);
+ } else {
+ new_data = nullptr;
+ }
- Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
- Local<Object> obj = env->buffer_constructor_function()->NewInstance(1, &arg);
+ smalloc::Alloc(env, obj, new_data, length);
- // TODO(trevnorris): done like this to handle HasInstance since only checks
- // if external array data has been set, but would like to use a better
- // approach if v8 provided one.
- char* new_data;
+ return scope.Escape(obj);
+ }
+
+ // V8 currently only allows a maximum Typed Array index of max Smi.
+ if (!IsValidSmi(length)) {
+ return Local<Object>();
+ }
+
+ void* new_data;
if (length > 0) {
- new_data = static_cast<char*>(malloc(length));
+ CHECK_NE(data, nullptr);
+ new_data = malloc(length);
+ // NOTE: API change. Must check .IsEmpty() on the return object to see if
+ // the data was able to be allocated.
if (new_data == nullptr)
- FatalError("node::Buffer::New(const char*, size_t)", "Out Of Memory");
+ return Local<Object>();
memcpy(new_data, data, length);
} else {
new_data = nullptr;
}
- smalloc::Alloc(env, obj, new_data, length);
+ Local<ArrayBuffer> ab =
+ ArrayBuffer::New(env->isolate(),
+ new_data,
+ length,
+ ArrayBufferCreationMode::kInternalized);
+ Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
+ ui->SetPrototype(env->buffer_prototype_object());
- return scope.Escape(obj);
+ return scope.Escape(ui);
}
@@ -196,6 +293,7 @@ Local<Object> New(Environment* env,
void* hint) {
EscapableHandleScope scope(env->isolate());
+ // TODO(trevnorris): IMPLEMENT
CHECK_LE(length, kMaxLength);
Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
@@ -207,7 +305,7 @@ Local<Object> New(Environment* env,
}
-Local<Object> Use(Isolate* isolate, char* data, uint32_t length) {
+Local<Object> Use(Isolate* isolate, char* data, size_t length) {
Environment* env = Environment::GetCurrent(isolate);
EscapableHandleScope handle_scope(env->isolate());
Local<Object> obj = Buffer::Use(env, data, length);
@@ -215,17 +313,98 @@ Local<Object> Use(Isolate* isolate, char* data, uint32_t length) {
}
-Local<Object> Use(Environment* env, char* data, uint32_t length) {
+Local<Object> Use(Environment* env, char* data, size_t length) {
EscapableHandleScope scope(env->isolate());
- CHECK_LE(length, kMaxLength);
+ if (using_old_buffer) {
+ CHECK_LE(length, kMaxLength);
- Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
- Local<Object> obj = env->buffer_constructor_function()->NewInstance(1, &arg);
+ Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
+ Local<Object> obj =
+ env->buffer_constructor_function()->NewInstance(1, &arg);
- smalloc::Alloc(env, obj, data, length);
+ smalloc::Alloc(env, obj, data, length);
- return scope.Escape(obj);
+ return scope.Escape(obj);
+ }
+
+ if (length > 0) {
+ CHECK_NE(data, nullptr);
+ CHECK(IsValidSmi(length));
+ }
+
+ Local<ArrayBuffer> ab =
+ ArrayBuffer::New(env->isolate(),
+ data,
+ length,
+ ArrayBufferCreationMode::kInternalized);
+ Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
+ ui->SetPrototype(env->buffer_prototype_object());
+ return scope.Escape(ui);
+}
+
+
+void Create(const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+ Environment* env = Environment::GetCurrent(args);
+
+ CHECK(args[0]->IsNumber());
+
+ int64_t length = args[0]->IntegerValue();
+
+ if (!IsValidSmi(length)) {
+ return env->ThrowRangeError("invalid Buffer length");
+ }
+
+ void* data;
+ if (length > 0) {
+ data = malloc(length);
+ if (data == nullptr)
+ return env->ThrowRangeError("invalid Buffer length");
+ } else {
+ data = nullptr;
+ }
+
+ Local<ArrayBuffer> ab =
+ ArrayBuffer::New(isolate,
+ data,
+ length,
+ ArrayBufferCreationMode::kInternalized);
+ Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
+ ui->SetPrototype(env->buffer_prototype_object());
+ args.GetReturnValue().Set(ui);
+}
+
+
+void CreateFromString(const FunctionCallbackInfo<Value>& args) {
+ CHECK(args[0]->IsString());
+ CHECK(args[1]->IsString());
+
+ enum encoding enc = ParseEncoding(args.GetIsolate(),
+ args[1].As<String>(),
+ UTF8);
+ Local<Object> buf = New(args.GetIsolate(), args[0].As<String>(), enc);
+ args.GetReturnValue().Set(buf);
+}
+
+
+void Slice(const FunctionCallbackInfo<Value>& args) {
+ CHECK(args[0]->IsUint8Array());
+ CHECK(args[1]->IsNumber());
+ CHECK(args[2]->IsNumber());
+ Environment* env = Environment::GetCurrent(args);
+ Local<Uint8Array> ab_ui = args[0].As<Uint8Array>();
+ Local<ArrayBuffer> ab = ab_ui->Buffer();
+ ArrayBuffer::Contents ab_c = ab->GetContents();
+ size_t offset = ab_ui->ByteOffset();
+ size_t start = args[1]->NumberValue() + offset;
+ size_t end = args[2]->NumberValue() + offset;
+ CHECK_GE(end, start);
+ size_t size = end - start;
+ CHECK_GE(ab_c.ByteLength(), start + size);
+ Local<Uint8Array> ui = Uint8Array::New(ab, start, size);
+ ui->SetPrototype(env->buffer_prototype_object());
+ args.GetReturnValue().Set(ui);
}
@@ -237,7 +416,12 @@ void StringSlice(const FunctionCallbackInfo<Value>& args) {
THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
ARGS_THIS_DEC(ts_obj);
- ARGS_THIS(args.This(), ts_obj);
+
+ if (using_old_buffer) {
+ ARGS_THIS(args.This(), ts_obj);
+ } else {
+ SPREAD_ARG(args.This(), ts_obj);
+ }
if (ts_obj_length == 0)
return args.GetReturnValue().SetEmptyString();
@@ -252,10 +436,16 @@ void StringSlice(const FunctionCallbackInfo<Value>& args) {
template <>
void StringSlice<UCS2>(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
- ARGS_THIS_DEC(ts_obj);
THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
- ARGS_THIS(args.This(), ts_obj);
+
+ ARGS_THIS_DEC(ts_obj);
+
+ if (using_old_buffer) {
+ ARGS_THIS(args.This(), ts_obj);
+ } else {
+ SPREAD_ARG(args.This(), ts_obj);
+ }
if (ts_obj_length == 0)
return args.GetReturnValue().SetEmptyString();
@@ -329,11 +519,22 @@ void Copy(const FunctionCallbackInfo<Value> &args) {
THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
- Local<Object> target_obj = args[0].As<Object>();
- size_t target_length = target->GetIndexedPropertiesExternalArrayDataLength();
- char* target_data = static_cast<char*>(
- target->GetIndexedPropertiesExternalArrayData());
+ Local<Object> target_obj = args[0]->ToObject(env->isolate());
+
+ ARGS_THIS_DEC(ts_obj);
+ ARGS_THIS_DEC(target);
+
+ if (using_old_buffer) {
+ ARGS_THIS(args.This(), ts_obj);
+ target_length = target_obj->GetIndexedPropertiesExternalArrayDataLength();
+ target_data = static_cast<char*>(
+ target_obj->GetIndexedPropertiesExternalArrayData());
+ } else {
+ SPREAD_ARG(args.This(), ts_obj);
+ SPREAD_ARG(target_obj, target);
+ }
+
size_t target_start;
size_t source_start;
size_t source_end;
@@ -364,7 +565,12 @@ void Copy(const FunctionCallbackInfo<Value> &args) {
void Fill(const FunctionCallbackInfo<Value>& args) {
THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
ARGS_THIS_DEC(ts_obj);
- ARGS_THIS(args[0].As<Object>(), ts_obj);
+
+ if (using_old_buffer) {
+ ARGS_THIS(args[0].As<Object>(), ts_obj);
+ } else {
+ SPREAD_ARG(args[0], ts_obj);
+ }
size_t start = args[2]->Uint32Value();
size_t end = args[3]->Uint32Value();
@@ -409,7 +615,12 @@ void StringWrite(const FunctionCallbackInfo<Value>& args) {
ARGS_THIS_DEC(ts_obj);
THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
- ARGS_THIS(args.This(), ts_obj);
+
+ if (using_old_buffer) {
+ ARGS_THIS(args.This(), ts_obj);
+ } else {
+ SPREAD_ARG(args.This(), ts_obj);
+ }
if (!args[0]->IsString())
return env->ThrowTypeError("Argument must be a string");
@@ -487,7 +698,12 @@ template <typename T, enum Endianness endianness>
void ReadFloatGeneric(const FunctionCallbackInfo<Value>& args) {
THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
ARGS_THIS_DEC(ts_obj);
- ARGS_THIS(args[0].As<Object>(), ts_obj);
+
+ if (using_old_buffer) {
+ ARGS_THIS(args[0].As<Object>(), ts_obj);
+ } else {
+ SPREAD_ARG(args[0], ts_obj);
+ }
uint32_t offset = args[1]->Uint32Value();
CHECK_LE(offset + sizeof(T), ts_obj_length);
@@ -530,7 +746,12 @@ void ReadDoubleBE(const FunctionCallbackInfo<Value>& args) {
template <typename T, enum Endianness endianness>
uint32_t WriteFloatGeneric(const FunctionCallbackInfo<Value>& args) {
ARGS_THIS_DEC(ts_obj);
- ARGS_THIS(args[0].As<Object>(), ts_obj);
+
+ if (using_old_buffer) {
+ ARGS_THIS(args[0].As<Object>(), ts_obj);
+ } else {
+ SPREAD_ARG(args[0], ts_obj);
+ }
T val = args[1]->NumberValue();
uint32_t offset = args[2]->Uint32Value();
@@ -588,26 +809,27 @@ void Compare(const FunctionCallbackInfo<Value> &args) {
THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
THROW_AND_RETURN_UNLESS_BUFFER(env, args[1]);
- Local<Object> obj_a = args[0].As<Object>();
- char* obj_a_data =
- static_cast<char*>(obj_a->GetIndexedPropertiesExternalArrayData());
- size_t obj_a_len = obj_a->GetIndexedPropertiesExternalArrayDataLength();
+ ARGS_THIS_DEC(obj_a);
+ ARGS_THIS_DEC(obj_b);
- Local<Object> obj_b = args[1].As<Object>();
- char* obj_b_data =
- static_cast<char*>(obj_b->GetIndexedPropertiesExternalArrayData());
- size_t obj_b_len = obj_b->GetIndexedPropertiesExternalArrayDataLength();
+ if (using_old_buffer) {
+ ARGS_THIS(args[0].As<Object>(), obj_a);
+ ARGS_THIS(args[1].As<Object>(), obj_b);
+ } else {
+ SPREAD_ARG(args[0], obj_a);
+ SPREAD_ARG(args[1], obj_b);
+ }
- size_t cmp_length = MIN(obj_a_len, obj_b_len);
+ size_t cmp_length = MIN(obj_a_length, obj_b_length);
int32_t val = memcmp(obj_a_data, obj_b_data, cmp_length);
// Normalize val to be an integer in the range of [1, -1] since
// implementations of memcmp() can vary by platform.
if (val == 0) {
- if (obj_a_len > obj_b_len)
+ if (obj_a_length > obj_b_length)
val = 1;
- else if (obj_a_len < obj_b_len)
+ else if (obj_a_length < obj_b_length)
val = -1;
} else {
if (val > 0)
@@ -642,7 +864,12 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
ARGS_THIS_DEC(ts_obj);
- ARGS_THIS(args[0].As<Object>(), ts_obj);
+
+ if (using_old_buffer) {
+ ARGS_THIS(args[0].As<Object>(), ts_obj);
+ } else {
+ SPREAD_ARG(args[0], ts_obj);
+ }
node::Utf8Value str(args.GetIsolate(), args[1]);
int32_t offset_i32 = args[2]->Int32Value();
@@ -675,7 +902,12 @@ void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
ARGS_THIS_DEC(ts_obj);
- ARGS_THIS(args[0].As<Object>(), ts_obj);
+
+ if (using_old_buffer) {
+ ARGS_THIS(args[0].As<Object>(), ts_obj);
+ } else {
+ SPREAD_ARG(args[0], ts_obj);
+ }
Local<Object> buf = args[1].As<Object>();
int32_t offset_i32 = args[2]->Int32Value();
@@ -714,7 +946,12 @@ void IndexOfNumber(const FunctionCallbackInfo<Value>& args) {
THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
ARGS_THIS_DEC(ts_obj);
- ARGS_THIS(args[0].As<Object>(), ts_obj);
+
+ if (using_old_buffer) {
+ ARGS_THIS(args[0].As<Object>(), ts_obj);
+ } else {
+ SPREAD_ARG(args[0], ts_obj);
+ }
uint32_t needle = args[1]->Uint32Value();
int32_t offset_i32 = args[2]->Int32Value();
@@ -743,15 +980,20 @@ void IndexOfNumber(const FunctionCallbackInfo<Value>& args) {
void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
- CHECK(args[0]->IsFunction());
-
- Local<Function> bv = args[0].As<Function>();
- env->set_buffer_constructor_function(bv);
- Local<Value> proto_v = bv->Get(env->prototype_string());
-
- CHECK(proto_v->IsObject());
+ Local<Object> proto;
- Local<Object> proto = proto_v.As<Object>();
+ if (using_old_buffer) {
+ CHECK(args[0]->IsFunction());
+ Local<Function> bv = args[0].As<Function>();
+ env->set_buffer_constructor_function(bv);
+ Local<Value> proto_v = bv->Get(env->prototype_string());
+ CHECK(proto_v->IsObject());
+ proto = proto_v.As<Object>();
+ } else {
+ CHECK(args[0]->IsObject());
+ proto = args[0].As<Object>();
+ env->set_buffer_prototype_object(proto);
+ }
env->SetMethod(proto, "asciiSlice", AsciiSlice);
env->SetMethod(proto, "base64Slice", Base64Slice);
@@ -770,9 +1012,11 @@ void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
env->SetMethod(proto, "copy", Copy);
// for backwards compatibility
- proto->ForceSet(env->offset_string(),
- Uint32::New(env->isolate(), 0),
- v8::ReadOnly);
+ if (using_old_buffer) {
+ proto->ForceSet(env->offset_string(),
+ Uint32::New(env->isolate(), 0),
+ v8::ReadOnly);
+ }
}
@@ -782,7 +1026,10 @@ void Initialize(Handle<Object> target,
Environment* env = Environment::GetCurrent(context);
env->SetMethod(target, "setupBufferJS", SetupBufferJS);
+ env->SetMethod(target, "create", Create);
+ env->SetMethod(target, "createFromString", CreateFromString);
+ env->SetMethod(target, "slice", Slice);
env->SetMethod(target, "byteLengthUtf8", ByteLengthUtf8);
env->SetMethod(target, "compare", Compare);
env->SetMethod(target, "fill", Fill);