const binding = process.binding('buffer');
const internalUtil = require('internal/util');
+const bindingObj = {};
exports.Buffer = Buffer;
exports.SlowBuffer = SlowBuffer;
var poolSize, poolOffset, allocPool;
+binding.setupBufferJS(Buffer.prototype, bindingObj);
+const flags = bindingObj.flags;
+const kNoZeroFill = 0;
+
+
function createPool() {
poolSize = Buffer.poolSize;
- allocPool = binding.create(poolSize);
+ flags[kNoZeroFill] = 1;
+ allocPool = new Uint8Array(poolSize);
+ Object.setPrototypeOf(allocPool, Buffer.prototype);
poolOffset = 0;
}
+createPool();
function alignPool() {
// Unusual.
return fromObject(arg);
-};
+}
Buffer.prototype.__proto__ = Uint8Array.prototype;
Buffer.__proto__ = Uint8Array;
-binding.setupBufferJS(Buffer.prototype);
-// Buffer prototype must be past before creating our first pool.
-createPool();
-
-
function SlowBuffer(length) {
if (+length != length)
length = 0;
- return binding.create(+length);
-};
+ flags[kNoZeroFill] = 1;
+ const ui8 = new Uint8Array(+length);
+ Object.setPrototypeOf(ui8, Buffer.prototype);
+ return ui8;
+}
SlowBuffer.prototype.__proto__ = Buffer.prototype;
SlowBuffer.__proto__ = Buffer;
function allocate(size) {
if (size === 0)
- return binding.create(0);
+ return SlowBuffer(0);
if (size < (Buffer.poolSize >>> 1)) {
if (size > (poolSize - poolOffset))
createPool();
alignPool();
return b;
} else {
- return binding.create(size);
+ flags[kNoZeroFill] = 1;
+ const ui8 = new Uint8Array(size);
+ Object.setPrototypeOf(ui8, Buffer.prototype);
+ return ui8;
}
}
last_threw_ = value;
}
+inline Environment::ArrayBufferAllocatorInfo::ArrayBufferAllocatorInfo() {
+ for (int i = 0; i < kFieldsCount; ++i)
+ fields_[i] = 0;
+}
+
+inline uint32_t* Environment::ArrayBufferAllocatorInfo::fields() {
+ return fields_;
+}
+
+inline int Environment::ArrayBufferAllocatorInfo::fields_count() const {
+ return kFieldsCount;
+}
+
+inline bool Environment::ArrayBufferAllocatorInfo::no_zero_fill() const {
+ return fields_[kNoZeroFill] != 0;
+}
+
+inline void Environment::ArrayBufferAllocatorInfo::reset_fill_flag() {
+ fields_[kNoZeroFill] = 0;
+}
+
inline Environment* Environment::New(v8::Local<v8::Context> context,
uv_loop_t* loop) {
Environment* env = new Environment(context, loop);
return &tick_info_;
}
+inline Environment::ArrayBufferAllocatorInfo*
+ Environment::array_buffer_allocator_info() {
+ return &array_buffer_allocator_info_;
+}
+
inline uint64_t Environment::timer_base() const {
return timer_base_;
}
DISALLOW_COPY_AND_ASSIGN(TickInfo);
};
+ class ArrayBufferAllocatorInfo {
+ public:
+ inline uint32_t* fields();
+ inline int fields_count() const;
+ inline bool no_zero_fill() const;
+ inline void reset_fill_flag();
+
+ private:
+ friend class Environment; // So we can call the constructor.
+ inline ArrayBufferAllocatorInfo();
+
+ enum Fields {
+ kNoZeroFill,
+ kFieldsCount
+ };
+
+ uint32_t fields_[kFieldsCount];
+
+ DISALLOW_COPY_AND_ASSIGN(ArrayBufferAllocatorInfo);
+ };
+
typedef void (*HandleCleanupCb)(Environment* env,
uv_handle_t* handle,
void* arg);
inline AsyncHooks* async_hooks();
inline DomainFlag* domain_flag();
inline TickInfo* tick_info();
+ inline ArrayBufferAllocatorInfo* array_buffer_allocator_info();
inline uint64_t timer_base() const;
static inline Environment* from_cares_timer_handle(uv_timer_t* handle);
AsyncHooks async_hooks_;
DomainFlag domain_flag_;
TickInfo tick_info_;
+ ArrayBufferAllocatorInfo array_buffer_allocator_info_;
const uint64_t timer_base_;
uv_timer_t cares_timer_handle_;
ares_channel cares_channel_;
#endif
+void* ArrayBufferAllocator::Allocate(size_t size) {
+ if (env_ == nullptr || !env_->array_buffer_allocator_info()->no_zero_fill())
+ return calloc(size, 1);
+ env_->array_buffer_allocator_info()->reset_fill_flag();
+ return malloc(size);
+}
+
+
void SetupDomainUse(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
static void StartNodeInstance(void* arg) {
NodeInstanceData* instance_data = static_cast<NodeInstanceData*>(arg);
Isolate::CreateParams params;
- ArrayBufferAllocator array_buffer_allocator;
- params.array_buffer_allocator = &array_buffer_allocator;
+ ArrayBufferAllocator* array_buffer_allocator = new ArrayBufferAllocator();
+ params.array_buffer_allocator = array_buffer_allocator;
Isolate* isolate = Isolate::New(params);
if (track_heap_objects) {
isolate->GetHeapProfiler()->StartTrackingHeapObjects(true);
HandleScope handle_scope(isolate);
Local<Context> context = Context::New(isolate);
Environment* env = CreateEnvironment(isolate, context, instance_data);
+ array_buffer_allocator->set_env(env);
Context::Scope context_scope(context);
if (instance_data->is_main())
env->set_using_abort_on_uncaught_exc(abort_on_uncaught_exception);
__lsan_do_leak_check();
#endif
+ array_buffer_allocator->set_env(nullptr);
env->Dispose();
env = nullptr;
}
CHECK_NE(isolate, nullptr);
isolate->Dispose();
isolate = nullptr;
+ delete array_buffer_allocator;
if (instance_data->is_main())
node_isolate = nullptr;
}
using v8::Persistent;
using v8::String;
using v8::Uint32;
+using v8::Uint32Array;
using v8::Uint8Array;
using v8::Value;
using v8::WeakCallbackData;
}
-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 (length < 0 || length > kMaxLength) {
- return env->ThrowRangeError("invalid Buffer length");
- }
-
- void* data;
- if (length > 0) {
- data = malloc(length);
- if (data == nullptr) {
- return env->ThrowRangeError(
- "Buffer allocation failed - process out of memory");
- }
- } else {
- data = nullptr;
- }
-
- Local<ArrayBuffer> ab =
- ArrayBuffer::New(isolate,
- data,
- length,
- ArrayBufferCreationMode::kInternalized);
- Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
- Maybe<bool> mb =
- ui->SetPrototype(env->context(), env->buffer_prototype_object());
- if (!mb.FromMaybe(false))
- return env->ThrowError("Unable to set Object prototype");
- args.GetReturnValue().Set(ui);
-}
-
-
void CreateFromString(const FunctionCallbackInfo<Value>& args) {
CHECK(args[0]->IsString());
CHECK(args[1]->IsString());
env->SetMethod(proto, "utf8Write", Utf8Write);
env->SetMethod(proto, "copy", Copy);
+
+ CHECK(args[1]->IsObject());
+ Local<Object> bObj = args[1].As<Object>();
+
+ uint32_t* const fields = env->array_buffer_allocator_info()->fields();
+ uint32_t const fields_count =
+ env->array_buffer_allocator_info()->fields_count();
+
+ Local<ArrayBuffer> array_buffer =
+ ArrayBuffer::New(env->isolate(), fields, sizeof(*fields) * fields_count);
+
+ bObj->Set(String::NewFromUtf8(env->isolate(), "flags"),
+ Uint32Array::New(array_buffer, 0, fields_count));
}
Environment* env = Environment::GetCurrent(context);
env->SetMethod(target, "setupBufferJS", SetupBufferJS);
- env->SetMethod(target, "create", Create);
env->SetMethod(target, "createFromString", CreateFromString);
env->SetMethod(target, "createFromArrayBuffer", CreateFromArrayBuffer);
return ThrowUVException(isolate, errorno, syscall, message, path);
})
-struct ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
- virtual void* Allocate(size_t size) {
- return calloc(size, 1);
- }
+class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
+ public:
+ ArrayBufferAllocator() { }
- virtual void* AllocateUninitialized(size_t size) {
- return malloc(size);
- }
+ inline void set_env(Environment* env) { env_ = env; }
- virtual void Free(void* data, size_t) {
- free(data);
- }
+ virtual void* Allocate(size_t size); // Defined in src/node.cc
+ virtual void* AllocateUninitialized(size_t size) { return malloc(size); }
+ virtual void Free(void* data, size_t) { free(data); }
+
+ private:
+ Environment* env_;
};
enum NodeInstanceType { MAIN, WORKER };