diff --git a/node.gyp b/node.gyp index 0829cd69c4..db40b6a781 100644 --- a/node.gyp +++ b/node.gyp @@ -84,6 +84,7 @@ 'src/node_zlib.cc', 'src/pipe_wrap.cc', 'src/stream_wrap.cc', + 'src/slab_allocator.cc', 'src/tcp_wrap.cc', 'src/timer_wrap.cc', 'src/tty_wrap.cc', @@ -107,6 +108,7 @@ 'src/node_version.h', 'src/pipe_wrap.h', 'src/req_wrap.h', + 'src/slab_allocator.h', 'src/stream_wrap.h', 'src/v8_typed_array.h', 'deps/http_parser/http_parser.h', diff --git a/src/slab_allocator.cc b/src/slab_allocator.cc new file mode 100644 index 0000000000..504557a555 --- /dev/null +++ b/src/slab_allocator.cc @@ -0,0 +1,127 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +#include "v8.h" +#include "node.h" +#include "node_buffer.h" +#include "slab_allocator.h" +#include +#include +#include + + +using v8::Handle; +using v8::HandleScope; +using v8::Integer; +using v8::Local; +using v8::Null; +using v8::Object; +using v8::Persistent; +using v8::String; +using v8::Value; + + +namespace node { + +SlabAllocator::SlabAllocator(unsigned int size) { + size_ = ROUND_UP(size ? size : 1, 8192); + initialized_ = false; +} + + +SlabAllocator::~SlabAllocator() { + if (!initialized_) return; + slab_sym_.Clear(); + slab_sym_.Dispose(); + slab_.Clear(); + slab_.Dispose(); +} + + +void SlabAllocator::Initialize() { + HandleScope scope; + char sym[256]; + snprintf(sym, sizeof(sym), "slab_%p", this); // namespace object key + offset_ = 0; + last_ptr_ = NULL; + initialized_ = true; + slab_sym_ = Persistent::New(String::New(sym)); +} + + +static Local NewSlab(unsigned int size) { + HandleScope scope; + Local arg = Integer::NewFromUnsigned(ROUND_UP(size, 16)); + Local buf = Buffer::constructor_template + ->GetFunction() + ->NewInstance(1, &arg); + return scope.Close(buf); +} + + +char* SlabAllocator::Allocate(Handle obj, unsigned int size) { + HandleScope scope; + + assert(!obj.IsEmpty()); + + if (size == 0) return NULL; + if (!initialized_) Initialize(); + + if (size > size_) { + Local buf = NewSlab(size); + obj->SetHiddenValue(slab_sym_, buf); + return Buffer::Data(buf); + } + + if (slab_.IsEmpty() || offset_ + size > size_) { + slab_.Clear(); + slab_.Dispose(); + slab_ = Persistent::New(NewSlab(size_)); + offset_ = 0; + last_ptr_ = NULL; + } + + obj->SetHiddenValue(slab_sym_, slab_); + last_ptr_ = Buffer::Data(slab_) + offset_; + offset_ += size; + + return last_ptr_; +} + + +Local SlabAllocator::Shrink(Handle obj, + char* ptr, + unsigned int size) { + HandleScope scope; + Local slab_v = obj->GetHiddenValue(slab_sym_); + obj->SetHiddenValue(slab_sym_, Null()); + assert(!slab_v.IsEmpty()); + assert(slab_v->IsObject()); + Local slab = slab_v->ToObject(); + if (ptr && ptr == last_ptr_) { + last_ptr_ = NULL; + offset_ = ptr - Buffer::Data(slab) + ROUND_UP(size, 16); + } + return scope.Close(slab); +} + + +} // namespace node diff --git a/src/slab_allocator.h b/src/slab_allocator.h new file mode 100644 index 0000000000..6440bd4a07 --- /dev/null +++ b/src/slab_allocator.h @@ -0,0 +1,49 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +#include "v8.h" + +namespace node { + +class SlabAllocator { +public: + SlabAllocator(unsigned int size = 10485760); // default to 10M + ~SlabAllocator(); + + // allocate memory from slab, attaches the slice to `obj` + char* Allocate(v8::Handle obj, unsigned int size); + + // return excess memory to the slab, returns a handle to the parent buffer + v8::Local Shrink(v8::Handle obj, + char* ptr, + unsigned int size); + +private: + void Initialize(); + bool initialized_; + v8::Persistent slab_; + v8::Persistent slab_sym_; + unsigned int offset_; + unsigned int size_; + char* last_ptr_; +}; + +} // namespace node