mirror of
https://github.com/nodejs/node.git
synced 2025-05-06 20:08:02 +00:00
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>
This commit is contained in:
parent
1ed4e1328e
commit
e8734c034d
1141
lib/buffer.js
1141
lib/buffer.js
File diff suppressed because it is too large
Load Diff
1020
lib/internal/buffer_new.js
Normal file
1020
lib/internal/buffer_new.js
Normal file
File diff suppressed because it is too large
Load Diff
1140
lib/internal/buffer_old.js
Normal file
1140
lib/internal/buffer_old.js
Normal file
File diff suppressed because it is too large
Load Diff
3
node.gyp
3
node.gyp
@ -69,8 +69,9 @@
|
|||||||
'lib/v8.js',
|
'lib/v8.js',
|
||||||
'lib/vm.js',
|
'lib/vm.js',
|
||||||
'lib/zlib.js',
|
'lib/zlib.js',
|
||||||
|
|
||||||
'lib/internal/child_process.js',
|
'lib/internal/child_process.js',
|
||||||
|
'lib/internal/buffer_old.js',
|
||||||
|
'lib/internal/buffer_new.js',
|
||||||
'lib/internal/freelist.js',
|
'lib/internal/freelist.js',
|
||||||
'lib/internal/smalloc.js',
|
'lib/internal/smalloc.js',
|
||||||
'lib/internal/socket_list.js',
|
'lib/internal/socket_list.js',
|
||||||
|
@ -231,6 +231,7 @@ namespace node {
|
|||||||
V(async_hooks_post_function, v8::Function) \
|
V(async_hooks_post_function, v8::Function) \
|
||||||
V(binding_cache_object, v8::Object) \
|
V(binding_cache_object, v8::Object) \
|
||||||
V(buffer_constructor_function, v8::Function) \
|
V(buffer_constructor_function, v8::Function) \
|
||||||
|
V(buffer_prototype_object, v8::Object) \
|
||||||
V(context, v8::Context) \
|
V(context, v8::Context) \
|
||||||
V(domain_array, v8::Array) \
|
V(domain_array, v8::Array) \
|
||||||
V(fs_stats_constructor_function, v8::Function) \
|
V(fs_stats_constructor_function, v8::Function) \
|
||||||
|
25
src/node.cc
25
src/node.cc
@ -5,6 +5,7 @@
|
|||||||
#include "node_http_parser.h"
|
#include "node_http_parser.h"
|
||||||
#include "node_javascript.h"
|
#include "node_javascript.h"
|
||||||
#include "node_version.h"
|
#include "node_version.h"
|
||||||
|
#include "node_internals.h"
|
||||||
|
|
||||||
#if defined HAVE_PERFCTR
|
#if defined HAVE_PERFCTR
|
||||||
#include "node_counters.h"
|
#include "node_counters.h"
|
||||||
@ -146,6 +147,8 @@ static uv_async_t dispatch_debug_messages_async;
|
|||||||
static Isolate* node_isolate = nullptr;
|
static Isolate* node_isolate = nullptr;
|
||||||
static v8::Platform* default_platform;
|
static v8::Platform* default_platform;
|
||||||
|
|
||||||
|
bool using_old_buffer = false;
|
||||||
|
|
||||||
class ArrayBufferAllocator : public ArrayBuffer::Allocator {
|
class ArrayBufferAllocator : public ArrayBuffer::Allocator {
|
||||||
public:
|
public:
|
||||||
// Impose an upper limit to avoid out of memory errors that bring down
|
// Impose an upper limit to avoid out of memory errors that bring down
|
||||||
@ -165,23 +168,17 @@ ArrayBufferAllocator ArrayBufferAllocator::the_singleton;
|
|||||||
|
|
||||||
|
|
||||||
void* ArrayBufferAllocator::Allocate(size_t length) {
|
void* ArrayBufferAllocator::Allocate(size_t length) {
|
||||||
if (length > kMaxLength)
|
return calloc(length, 1);
|
||||||
return nullptr;
|
|
||||||
char* data = new char[length];
|
|
||||||
memset(data, 0, length);
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void* ArrayBufferAllocator::AllocateUninitialized(size_t length) {
|
void* ArrayBufferAllocator::AllocateUninitialized(size_t length) {
|
||||||
if (length > kMaxLength)
|
return malloc(length);
|
||||||
return nullptr;
|
|
||||||
return new char[length];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ArrayBufferAllocator::Free(void* data, size_t length) {
|
void ArrayBufferAllocator::Free(void* data, size_t length) {
|
||||||
delete[] static_cast<char*>(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2844,6 +2841,11 @@ void SetupProcessObject(Environment* env,
|
|||||||
// after LoadEnvironment() has run.
|
// after LoadEnvironment() has run.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --use-old_buffer
|
||||||
|
if (using_old_buffer) {
|
||||||
|
READONLY_PROPERTY(process, "useOldBuffer", True(env->isolate()));
|
||||||
|
}
|
||||||
|
|
||||||
size_t exec_path_len = 2 * PATH_MAX;
|
size_t exec_path_len = 2 * PATH_MAX;
|
||||||
char* exec_path = new char[exec_path_len];
|
char* exec_path = new char[exec_path_len];
|
||||||
Local<String> exec_path_value;
|
Local<String> exec_path_value;
|
||||||
@ -3072,6 +3074,7 @@ static void PrintHelp() {
|
|||||||
" --trace-deprecation show stack traces on deprecations\n"
|
" --trace-deprecation show stack traces on deprecations\n"
|
||||||
" --trace-sync-io show stack trace when use of sync IO\n"
|
" --trace-sync-io show stack trace when use of sync IO\n"
|
||||||
" is detected after the first tick\n"
|
" is detected after the first tick\n"
|
||||||
|
" --use-old-buffer Revert to old Buffer implementation\n"
|
||||||
" --v8-options print v8 command line options\n"
|
" --v8-options print v8 command line options\n"
|
||||||
#if defined(NODE_HAVE_I18N_SUPPORT)
|
#if defined(NODE_HAVE_I18N_SUPPORT)
|
||||||
" --icu-data-dir=dir set ICU data load path to dir\n"
|
" --icu-data-dir=dir set ICU data load path to dir\n"
|
||||||
@ -3208,6 +3211,10 @@ static void ParseArgs(int* argc,
|
|||||||
#endif
|
#endif
|
||||||
} else if (strcmp(arg, "--expose-internals") == 0 ||
|
} else if (strcmp(arg, "--expose-internals") == 0 ||
|
||||||
strcmp(arg, "--expose_internals") == 0) {
|
strcmp(arg, "--expose_internals") == 0) {
|
||||||
|
} else if (strcmp(arg, "--use-old-buffer") == 0 ||
|
||||||
|
strcmp(arg, "--use_old_buffer") == 0) {
|
||||||
|
using_old_buffer = true;
|
||||||
|
|
||||||
// consumed in js
|
// consumed in js
|
||||||
} else {
|
} else {
|
||||||
// V8 option. Pass through as-is.
|
// V8 option. Pass through as-is.
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
#include "env-inl.h"
|
#include "env-inl.h"
|
||||||
#include "smalloc.h"
|
#include "smalloc.h"
|
||||||
#include "string_bytes.h"
|
#include "string_bytes.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "util-inl.h"
|
||||||
#include "v8-profiler.h"
|
#include "v8-profiler.h"
|
||||||
#include "v8.h"
|
#include "v8.h"
|
||||||
|
|
||||||
@ -22,6 +24,16 @@
|
|||||||
size_t name##_length; \
|
size_t name##_length; \
|
||||||
char* name##_data;
|
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) \
|
#define ARGS_THIS(argT, name) \
|
||||||
Local<Object> name = argT; \
|
Local<Object> name = argT; \
|
||||||
name##_length = name->GetIndexedPropertiesExternalArrayDataLength(); \
|
name##_length = name->GetIndexedPropertiesExternalArrayDataLength(); \
|
||||||
@ -42,6 +54,8 @@
|
|||||||
namespace node {
|
namespace node {
|
||||||
namespace Buffer {
|
namespace Buffer {
|
||||||
|
|
||||||
|
using v8::ArrayBuffer;
|
||||||
|
using v8::ArrayBufferCreationMode;
|
||||||
using v8::Context;
|
using v8::Context;
|
||||||
using v8::EscapableHandleScope;
|
using v8::EscapableHandleScope;
|
||||||
using v8::Function;
|
using v8::Function;
|
||||||
@ -55,6 +69,7 @@ using v8::Number;
|
|||||||
using v8::Object;
|
using v8::Object;
|
||||||
using v8::String;
|
using v8::String;
|
||||||
using v8::Uint32;
|
using v8::Uint32;
|
||||||
|
using v8::Uint8Array;
|
||||||
using v8::Value;
|
using v8::Value;
|
||||||
|
|
||||||
|
|
||||||
@ -64,10 +79,19 @@ bool HasInstance(Handle<Value> val) {
|
|||||||
|
|
||||||
|
|
||||||
bool HasInstance(Handle<Object> obj) {
|
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;
|
return false;
|
||||||
v8::ExternalArrayType type = obj->GetIndexedPropertiesExternalArrayDataType();
|
Local<Uint8Array> array = obj.As<Uint8Array>();
|
||||||
return type == v8::kExternalUint8Array;
|
Environment* env = Environment::GetCurrent(array->GetIsolate());
|
||||||
|
return array->GetPrototype()->StrictEquals(env->buffer_prototype_object());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -80,8 +104,15 @@ char* Data(Handle<Value> val) {
|
|||||||
|
|
||||||
|
|
||||||
char* Data(Handle<Object> obj) {
|
char* Data(Handle<Object> obj) {
|
||||||
CHECK(obj->HasIndexedPropertiesInExternalArrayData());
|
if (using_old_buffer) {
|
||||||
return static_cast<char*>(obj->GetIndexedPropertiesExternalArrayData());
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -92,8 +123,14 @@ size_t Length(Handle<Value> val) {
|
|||||||
|
|
||||||
|
|
||||||
size_t Length(Handle<Object> obj) {
|
size_t Length(Handle<Object> obj) {
|
||||||
CHECK(obj->HasIndexedPropertiesInExternalArrayData());
|
if (using_old_buffer) {
|
||||||
return obj->GetIndexedPropertiesExternalArrayDataLength();
|
CHECK(obj->HasIndexedPropertiesInExternalArrayData());
|
||||||
|
return obj->GetIndexedPropertiesExternalArrayDataLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(obj->IsUint8Array());
|
||||||
|
Local<Uint8Array> ui = obj.As<Uint8Array>();
|
||||||
|
return ui->ByteLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -101,11 +138,20 @@ Local<Object> New(Isolate* isolate, Handle<String> string, enum encoding enc) {
|
|||||||
EscapableHandleScope scope(isolate);
|
EscapableHandleScope scope(isolate);
|
||||||
|
|
||||||
size_t length = StringBytes::Size(isolate, string, enc);
|
size_t length = StringBytes::Size(isolate, string, enc);
|
||||||
|
char* data = static_cast<char*>(malloc(length));
|
||||||
|
|
||||||
Local<Object> buf = New(isolate, length);
|
if (data == nullptr)
|
||||||
char* data = Buffer::Data(buf);
|
return Local<Object>();
|
||||||
StringBytes::Write(isolate, data, length, string, enc);
|
|
||||||
|
|
||||||
|
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);
|
return scope.Escape(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,19 +163,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) {
|
Local<Object> New(Environment* env, size_t length) {
|
||||||
EscapableHandleScope scope(env->isolate());
|
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<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
|
||||||
Local<Object> obj = env->buffer_constructor_function()->NewInstance(1, &arg);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -141,33 +212,59 @@ Local<Object> New(Isolate* isolate, const char* data, size_t length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO(trevnorris): for backwards compatibility this is left to copy the data,
|
// Make a copy of "data". Why this isn't called "Copy", we'll never know.
|
||||||
// but for consistency w/ the other should use data. And a copy version renamed
|
|
||||||
// to something else.
|
|
||||||
Local<Object> New(Environment* env, const char* data, size_t length) {
|
Local<Object> New(Environment* env, const char* data, size_t length) {
|
||||||
EscapableHandleScope scope(env->isolate());
|
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<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
|
||||||
Local<Object> obj = env->buffer_constructor_function()->NewInstance(1, &arg);
|
Local<Object> obj =
|
||||||
|
env->buffer_constructor_function()->NewInstance(1, &arg);
|
||||||
|
|
||||||
// TODO(trevnorris): done like this to handle HasInstance since only checks
|
char* new_data;
|
||||||
// if external array data has been set, but would like to use a better
|
if (length > 0) {
|
||||||
// approach if v8 provided one.
|
new_data = static_cast<char*>(malloc(length));
|
||||||
char* new_data;
|
if (new_data == nullptr)
|
||||||
|
FatalError("node::Buffer::New(const char*, size_t)", "Out Of Memory");
|
||||||
|
memcpy(new_data, data, length);
|
||||||
|
} else {
|
||||||
|
new_data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
smalloc::Alloc(env, obj, new_data, length);
|
||||||
|
|
||||||
|
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) {
|
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)
|
if (new_data == nullptr)
|
||||||
FatalError("node::Buffer::New(const char*, size_t)", "Out Of Memory");
|
return Local<Object>();
|
||||||
memcpy(new_data, data, length);
|
memcpy(new_data, data, length);
|
||||||
} else {
|
} else {
|
||||||
new_data = nullptr;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -190,6 +287,7 @@ Local<Object> New(Environment* env,
|
|||||||
void* hint) {
|
void* hint) {
|
||||||
EscapableHandleScope scope(env->isolate());
|
EscapableHandleScope scope(env->isolate());
|
||||||
|
|
||||||
|
// TODO(trevnorris): IMPLEMENT
|
||||||
CHECK_LE(length, kMaxLength);
|
CHECK_LE(length, kMaxLength);
|
||||||
|
|
||||||
Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
|
Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
|
||||||
@ -201,7 +299,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);
|
Environment* env = Environment::GetCurrent(isolate);
|
||||||
EscapableHandleScope handle_scope(env->isolate());
|
EscapableHandleScope handle_scope(env->isolate());
|
||||||
Local<Object> obj = Buffer::Use(env, data, length);
|
Local<Object> obj = Buffer::Use(env, data, length);
|
||||||
@ -209,17 +307,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());
|
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<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
|
||||||
Local<Object> obj = env->buffer_constructor_function()->NewInstance(1, &arg);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -229,7 +408,12 @@ void StringSlice(const FunctionCallbackInfo<Value>& args) {
|
|||||||
Isolate* isolate = env->isolate();
|
Isolate* isolate = env->isolate();
|
||||||
ARGS_THIS_DEC(ts_obj);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
SLICE_START_END(args[0], args[1], ts_obj_length)
|
SLICE_START_END(args[0], args[1], ts_obj_length)
|
||||||
|
|
||||||
args.GetReturnValue().Set(
|
args.GetReturnValue().Set(
|
||||||
@ -242,7 +426,12 @@ void StringSlice<UCS2>(const FunctionCallbackInfo<Value>& args) {
|
|||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
ARGS_THIS_DEC(ts_obj);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
SLICE_START_END(args[0], args[1], ts_obj_length)
|
SLICE_START_END(args[0], args[1], ts_obj_length)
|
||||||
length /= 2;
|
length /= 2;
|
||||||
|
|
||||||
@ -313,13 +502,20 @@ void Copy(const FunctionCallbackInfo<Value> &args) {
|
|||||||
if (!HasInstance(args[0]))
|
if (!HasInstance(args[0]))
|
||||||
return env->ThrowTypeError("first arg should be a Buffer");
|
return env->ThrowTypeError("first arg should be a Buffer");
|
||||||
|
|
||||||
Local<Object> target = args[0]->ToObject(env->isolate());
|
Local<Object> target_obj = args[0]->ToObject(env->isolate());
|
||||||
ARGS_THIS_DEC(ts_obj);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
ARGS_THIS(args.This(), ts_obj);
|
|
||||||
size_t target_length = target->GetIndexedPropertiesExternalArrayDataLength();
|
|
||||||
char* target_data = static_cast<char*>(
|
|
||||||
target->GetIndexedPropertiesExternalArrayData());
|
|
||||||
size_t target_start;
|
size_t target_start;
|
||||||
size_t source_start;
|
size_t source_start;
|
||||||
size_t source_end;
|
size_t source_end;
|
||||||
@ -349,7 +545,12 @@ void Copy(const FunctionCallbackInfo<Value> &args) {
|
|||||||
|
|
||||||
void Fill(const FunctionCallbackInfo<Value>& args) {
|
void Fill(const FunctionCallbackInfo<Value>& args) {
|
||||||
ARGS_THIS_DEC(ts_obj);
|
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 start = args[2]->Uint32Value();
|
||||||
size_t end = args[3]->Uint32Value();
|
size_t end = args[3]->Uint32Value();
|
||||||
@ -393,7 +594,11 @@ void StringWrite(const FunctionCallbackInfo<Value>& args) {
|
|||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
ARGS_THIS_DEC(ts_obj);
|
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 (!args[0]->IsString())
|
if (!args[0]->IsString())
|
||||||
return env->ThrowTypeError("Argument must be a string");
|
return env->ThrowTypeError("Argument must be a string");
|
||||||
@ -470,7 +675,12 @@ static inline void Swizzle(char* start, unsigned int len) {
|
|||||||
template <typename T, enum Endianness endianness>
|
template <typename T, enum Endianness endianness>
|
||||||
void ReadFloatGeneric(const FunctionCallbackInfo<Value>& args) {
|
void ReadFloatGeneric(const FunctionCallbackInfo<Value>& args) {
|
||||||
ARGS_THIS_DEC(ts_obj);
|
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();
|
uint32_t offset = args[1]->Uint32Value();
|
||||||
CHECK_LE(offset + sizeof(T), ts_obj_length);
|
CHECK_LE(offset + sizeof(T), ts_obj_length);
|
||||||
@ -513,7 +723,12 @@ void ReadDoubleBE(const FunctionCallbackInfo<Value>& args) {
|
|||||||
template <typename T, enum Endianness endianness>
|
template <typename T, enum Endianness endianness>
|
||||||
uint32_t WriteFloatGeneric(const FunctionCallbackInfo<Value>& args) {
|
uint32_t WriteFloatGeneric(const FunctionCallbackInfo<Value>& args) {
|
||||||
ARGS_THIS_DEC(ts_obj);
|
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();
|
T val = args[1]->NumberValue();
|
||||||
uint32_t offset = args[2]->Uint32Value();
|
uint32_t offset = args[2]->Uint32Value();
|
||||||
@ -562,26 +777,27 @@ void ByteLengthUtf8(const FunctionCallbackInfo<Value> &args) {
|
|||||||
|
|
||||||
|
|
||||||
void Compare(const FunctionCallbackInfo<Value> &args) {
|
void Compare(const FunctionCallbackInfo<Value> &args) {
|
||||||
Local<Object> obj_a = args[0].As<Object>();
|
ARGS_THIS_DEC(obj_a);
|
||||||
char* obj_a_data =
|
ARGS_THIS_DEC(obj_b);
|
||||||
static_cast<char*>(obj_a->GetIndexedPropertiesExternalArrayData());
|
|
||||||
size_t obj_a_len = obj_a->GetIndexedPropertiesExternalArrayDataLength();
|
|
||||||
|
|
||||||
Local<Object> obj_b = args[1].As<Object>();
|
if (using_old_buffer) {
|
||||||
char* obj_b_data =
|
ARGS_THIS(args[0].As<Object>(), obj_a);
|
||||||
static_cast<char*>(obj_b->GetIndexedPropertiesExternalArrayData());
|
ARGS_THIS(args[1].As<Object>(), obj_b);
|
||||||
size_t obj_b_len = obj_b->GetIndexedPropertiesExternalArrayDataLength();
|
} 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);
|
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
|
// Normalize val to be an integer in the range of [1, -1] since
|
||||||
// implementations of memcmp() can vary by platform.
|
// implementations of memcmp() can vary by platform.
|
||||||
if (val == 0) {
|
if (val == 0) {
|
||||||
if (obj_a_len > obj_b_len)
|
if (obj_a_length > obj_b_length)
|
||||||
val = 1;
|
val = 1;
|
||||||
else if (obj_a_len < obj_b_len)
|
else if (obj_a_length < obj_b_length)
|
||||||
val = -1;
|
val = -1;
|
||||||
} else {
|
} else {
|
||||||
if (val > 0)
|
if (val > 0)
|
||||||
@ -616,7 +832,13 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
|
|||||||
ASSERT(args[2]->IsNumber());
|
ASSERT(args[2]->IsNumber());
|
||||||
|
|
||||||
ARGS_THIS_DEC(ts_obj);
|
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]);
|
node::Utf8Value str(args.GetIsolate(), args[1]);
|
||||||
int32_t offset_i32 = args[2]->Int32Value();
|
int32_t offset_i32 = args[2]->Int32Value();
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
@ -648,7 +870,13 @@ void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
|
|||||||
ASSERT(args[2]->IsNumber());
|
ASSERT(args[2]->IsNumber());
|
||||||
|
|
||||||
ARGS_THIS_DEC(ts_obj);
|
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>();
|
Local<Object> buf = args[1].As<Object>();
|
||||||
int32_t offset_i32 = args[2]->Int32Value();
|
int32_t offset_i32 = args[2]->Int32Value();
|
||||||
size_t buf_length = buf->GetIndexedPropertiesExternalArrayDataLength();
|
size_t buf_length = buf->GetIndexedPropertiesExternalArrayDataLength();
|
||||||
@ -686,7 +914,13 @@ void IndexOfNumber(const FunctionCallbackInfo<Value>& args) {
|
|||||||
ASSERT(args[2]->IsNumber());
|
ASSERT(args[2]->IsNumber());
|
||||||
|
|
||||||
ARGS_THIS_DEC(ts_obj);
|
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();
|
uint32_t needle = args[1]->Uint32Value();
|
||||||
int32_t offset_i32 = args[2]->Int32Value();
|
int32_t offset_i32 = args[2]->Int32Value();
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
@ -714,15 +948,20 @@ void IndexOfNumber(const FunctionCallbackInfo<Value>& args) {
|
|||||||
void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
|
void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
|
||||||
CHECK(args[0]->IsFunction());
|
Local<Object> proto;
|
||||||
|
|
||||||
Local<Function> bv = args[0].As<Function>();
|
if (using_old_buffer) {
|
||||||
env->set_buffer_constructor_function(bv);
|
CHECK(args[0]->IsFunction());
|
||||||
Local<Value> proto_v = bv->Get(env->prototype_string());
|
Local<Function> bv = args[0].As<Function>();
|
||||||
|
env->set_buffer_constructor_function(bv);
|
||||||
CHECK(proto_v->IsObject());
|
Local<Value> proto_v = bv->Get(env->prototype_string());
|
||||||
|
CHECK(proto_v->IsObject());
|
||||||
Local<Object> proto = proto_v.As<Object>();
|
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, "asciiSlice", AsciiSlice);
|
||||||
env->SetMethod(proto, "base64Slice", Base64Slice);
|
env->SetMethod(proto, "base64Slice", Base64Slice);
|
||||||
@ -741,9 +980,11 @@ void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
|
|||||||
env->SetMethod(proto, "copy", Copy);
|
env->SetMethod(proto, "copy", Copy);
|
||||||
|
|
||||||
// for backwards compatibility
|
// for backwards compatibility
|
||||||
proto->ForceSet(env->offset_string(),
|
if (using_old_buffer) {
|
||||||
Uint32::New(env->isolate(), 0),
|
proto->ForceSet(env->offset_string(),
|
||||||
v8::ReadOnly);
|
Uint32::New(env->isolate(), 0),
|
||||||
|
v8::ReadOnly);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -753,7 +994,10 @@ void Initialize(Handle<Object> target,
|
|||||||
Environment* env = Environment::GetCurrent(context);
|
Environment* env = Environment::GetCurrent(context);
|
||||||
|
|
||||||
env->SetMethod(target, "setupBufferJS", SetupBufferJS);
|
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, "byteLengthUtf8", ByteLengthUtf8);
|
||||||
env->SetMethod(target, "compare", Compare);
|
env->SetMethod(target, "compare", Compare);
|
||||||
env->SetMethod(target, "fill", Fill);
|
env->SetMethod(target, "fill", Fill);
|
||||||
|
@ -63,9 +63,9 @@ NODE_DEPRECATED("Use New(isolate, ...)",
|
|||||||
// TODO(trevnorris): should be New() for consistency
|
// TODO(trevnorris): should be New() for consistency
|
||||||
NODE_EXTERN v8::Local<v8::Object> Use(v8::Isolate* isolate,
|
NODE_EXTERN v8::Local<v8::Object> Use(v8::Isolate* isolate,
|
||||||
char* data,
|
char* data,
|
||||||
uint32_t len);
|
size_t len);
|
||||||
NODE_DEPRECATED("Use Use(isolate, ...)",
|
NODE_DEPRECATED("Use Use(isolate, ...)",
|
||||||
inline v8::Local<v8::Object> Use(char* data, uint32_t len) {
|
inline v8::Local<v8::Object> Use(char* data, size_t len) {
|
||||||
return Use(v8::Isolate::GetCurrent(), data, len);
|
return Use(v8::Isolate::GetCurrent(), data, len);
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ v8::Local<v8::Object> New(Environment* env,
|
|||||||
size_t length,
|
size_t length,
|
||||||
smalloc::FreeCallback callback,
|
smalloc::FreeCallback callback,
|
||||||
void* hint);
|
void* hint);
|
||||||
v8::Local<v8::Object> Use(Environment* env, char* data, uint32_t length);
|
v8::Local<v8::Object> Use(Environment* env, char* data, size_t length);
|
||||||
#endif // defined(NODE_WANT_INTERNALS)
|
#endif // defined(NODE_WANT_INTERNALS)
|
||||||
|
|
||||||
} // namespace Buffer
|
} // namespace Buffer
|
||||||
|
@ -17,6 +17,8 @@ namespace node {
|
|||||||
// Forward declaration
|
// Forward declaration
|
||||||
class Environment;
|
class Environment;
|
||||||
|
|
||||||
|
extern bool using_old_buffer;
|
||||||
|
|
||||||
// If persistent.IsWeak() == false, then do not call persistent.Reset()
|
// If persistent.IsWeak() == false, then do not call persistent.Reset()
|
||||||
// while the returned Local<T> is still in scope, it will destroy the
|
// while the returned Local<T> is still in scope, it will destroy the
|
||||||
// reference to the object.
|
// reference to the object.
|
||||||
|
@ -198,6 +198,14 @@ TypeName* Unwrap(v8::Local<v8::Object> object) {
|
|||||||
return static_cast<TypeName*>(pointer);
|
return static_cast<TypeName*>(pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool IsValidSmi(int64_t value) {
|
||||||
|
if (sizeof(int32_t) == sizeof(intptr_t)) {
|
||||||
|
return value >= -0x40000000LL && value <= 0x3fffffffLL;
|
||||||
|
} else {
|
||||||
|
return value >= -0x80000000LL && value <= 0x7fffffffLL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
|
||||||
#endif // SRC_UTIL_INL_H_
|
#endif // SRC_UTIL_INL_H_
|
||||||
|
@ -195,6 +195,8 @@ class Utf8Value {
|
|||||||
char str_st_[1024];
|
char str_st_[1024];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline bool IsValidSmi(int64_t value);
|
||||||
|
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
|
||||||
#endif // SRC_UTIL_H_
|
#endif // SRC_UTIL_H_
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
var common = require('../common');
|
|
||||||
var assert = require('assert');
|
|
||||||
|
|
||||||
var Buffer = require('buffer').Buffer;
|
|
||||||
|
|
||||||
var buff = new Buffer(Buffer.poolSize + 1);
|
|
||||||
var slicedBuffer = buff.slice();
|
|
||||||
assert.equal(slicedBuffer.parent,
|
|
||||||
buff,
|
|
||||||
'slicedBufffer should have its parent set to the original ' +
|
|
||||||
' buffer');
|
|
@ -310,8 +310,6 @@ assert.equal(b.parent, d.parent);
|
|||||||
var b = new SlowBuffer(5);
|
var b = new SlowBuffer(5);
|
||||||
var c = b.slice(0, 4);
|
var c = b.slice(0, 4);
|
||||||
var d = c.slice(0, 2);
|
var d = c.slice(0, 2);
|
||||||
assert.equal(b, c.parent);
|
|
||||||
assert.equal(b, d.parent);
|
|
||||||
|
|
||||||
|
|
||||||
// Bug regression test
|
// Bug regression test
|
||||||
@ -1054,10 +1052,6 @@ assert.equal(buf.readInt8(0), -1);
|
|||||||
// try to slice a zero length Buffer
|
// try to slice a zero length Buffer
|
||||||
// see https://github.com/joyent/node/issues/5881
|
// see https://github.com/joyent/node/issues/5881
|
||||||
SlowBuffer(0).slice(0, 1);
|
SlowBuffer(0).slice(0, 1);
|
||||||
// make sure a zero length slice doesn't set the .parent attribute
|
|
||||||
assert.equal(Buffer(5).slice(0, 0).parent, undefined);
|
|
||||||
// and make sure a proper slice does have a parent
|
|
||||||
assert.ok(typeof Buffer(5).slice(0, 5).parent === 'object');
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// Regression test for #5482: should throw but not assert in C++ land.
|
// Regression test for #5482: should throw but not assert in C++ land.
|
||||||
@ -1084,11 +1078,11 @@ assert.throws(function() {
|
|||||||
|
|
||||||
|
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
new Buffer(smalloc.kMaxLength + 1);
|
new Buffer((-1 >>> 0) + 1);
|
||||||
}, RangeError);
|
}, RangeError);
|
||||||
|
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
new SlowBuffer(smalloc.kMaxLength + 1);
|
new SlowBuffer((-1 >>> 0) + 1);
|
||||||
}, RangeError);
|
}, RangeError);
|
||||||
|
|
||||||
if (common.hasCrypto) {
|
if (common.hasCrypto) {
|
||||||
|
Loading…
Reference in New Issue
Block a user