Skip to content

Commit

Permalink
Merge pull request #35 from unbornchikken/io.js-3.0-support
Browse files Browse the repository at this point in the history
Io.js 3.0 support
  • Loading branch information
TooTallNate committed Aug 26, 2015
2 parents 53e7195 + f66ea11 commit 31fe46b
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 47 deletions.
2 changes: 2 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ environment:
- nodejs_version: "0.8"
- nodejs_version: "0.10"
- nodejs_version: "0.12"
- nodejs_version: "2.5"
- nodejs_version: "3.2"

platform:
- x86
Expand Down
88 changes: 41 additions & 47 deletions src/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ namespace {
// we could use `node::Buffer::kMaxLength`, but it's not defined on node v0.6.x
static const unsigned int kMaxLength = 0x3fffffff;

// get int64 from a value
inline int64_t GetInt64(Local<Value> value) {
return value->IsNumber() ? Nan::To<int64_t>(value).FromJust() : 0;
}

/*
* Returns the pointer address as a Number of the given Buffer instance.
* It's recommended to use `hexAddress()` in most cases instead of this function.
Expand All @@ -54,7 +59,7 @@ NAN_METHOD(Address) {
return Nan::ThrowTypeError("address: Buffer instance expected");
}

int64_t offset = info[1]->IntegerValue();
int64_t offset = GetInt64(info[1]);
char *ptr = Buffer::Data(buf.As<Object>()) + offset;
uintptr_t intptr = (uintptr_t)ptr;
Local<Number> rtn = Nan::New(static_cast<double>(intptr));
Expand All @@ -78,7 +83,7 @@ NAN_METHOD(HexAddress) {
return Nan::ThrowTypeError("hexAddress: Buffer instance expected");
}

int64_t offset = info[1]->IntegerValue();
int64_t offset = GetInt64(info[1]);
char *ptr = Buffer::Data(buf.As<Object>()) + offset;
char strbuf[30]; /* should be plenty... */
snprintf(strbuf, 30, "%p", ptr);
Expand Down Expand Up @@ -108,7 +113,7 @@ NAN_METHOD(IsNull) {
return Nan::ThrowTypeError("isNull: Buffer instance expected");
}

int64_t offset = info[1]->IntegerValue();
int64_t offset = GetInt64(info[1]);
char *ptr = Buffer::Data(buf.As<Object>()) + offset;
Local<Value> rtn = Nan::New(ptr == NULL);

Expand All @@ -130,12 +135,20 @@ const char *CheckEndianness() {
}

/*
* A callback that should never be invoked since the NULL pointer
* wrapper Buffer should never be collected
* Converts an arbitrary pointer to a node Buffer with specified length
*/

void unref_null_cb(char *data, void *hint) {
assert(0 && "NULL Buffer should never be garbage collected");
void wrap_pointer_cb(char *data, void *hint)
{
}

inline Local<Value> WrapPointer(char *ptr, size_t length) {
Nan::EscapableHandleScope scope;
return scope.Escape(Nan::NewBuffer(ptr, length, wrap_pointer_cb, NULL).ToLocalChecked());
}

inline Local<Value> WrapPointer(char *ptr) {
return WrapPointer(ptr, 0);
}

/*
Expand All @@ -144,13 +157,8 @@ void unref_null_cb(char *data, void *hint) {
* pointer in JS-land by doing something like: `ref.NULL[0]`.
*/

Local<Object> WrapNullPointer() {
Nan::EscapableHandleScope scope;
size_t buf_size = 0;
char *ptr = reinterpret_cast<char *>(NULL);
void *user_data = NULL;
Local<Object> buf = Nan::NewBuffer(ptr, buf_size, unref_null_cb, user_data).ToLocalChecked();
return scope.Escape<Object>(buf);
inline Local<Value> WrapNullPointer() {
return WrapPointer((char*)NULL, 0);
}

/*
Expand All @@ -168,7 +176,7 @@ NAN_METHOD(ReadObject) {
return Nan::ThrowTypeError("readObject: Buffer instance expected");
}

int64_t offset = info[1]->IntegerValue();
int64_t offset = GetInt64(info[1]);
char *ptr = Buffer::Data(buf.As<Object>()) + offset;

if (ptr == NULL) {
Expand Down Expand Up @@ -210,15 +218,15 @@ NAN_METHOD(WriteObject) {
return Nan::ThrowTypeError("writeObject: Buffer instance expected");
}

int64_t offset = info[1]->IntegerValue();
int64_t offset = GetInt64(info[1]);
char *ptr = Buffer::Data(buf.As<Object>()) + offset;

Nan::Persistent<Object>* pptr = reinterpret_cast<Nan::Persistent<Object>*>(ptr);
Local<Object> val = info[2].As<Object>();

bool persistent = info[3]->BooleanValue();
if (persistent) {
(*pptr).Reset(val);
(*pptr).Reset(val);
} else {
void *user_data = NULL;
Nan::Persistent<Object> p2(val);
Expand All @@ -229,15 +237,6 @@ NAN_METHOD(WriteObject) {
info.GetReturnValue().SetUndefined();
}

/*
* Callback function for when the SlowBuffer created from ReadPointer gets
* garbage collected. We don't have to do anything; Node frees the Buffer for us.
*/

void read_pointer_cb(char *data, void *hint) {
//fprintf(stderr, "read_pointer_cb\n");
}

/*
* Reads the memory address of the given "buf" pointer Buffer at the specified
* offset, and returns a new SlowBuffer instance from the memory address stored.
Expand All @@ -254,7 +253,7 @@ NAN_METHOD(ReadPointer) {
return Nan::ThrowTypeError("readPointer: Buffer instance expected as first argument");
}

int64_t offset = info[1]->IntegerValue();
int64_t offset = GetInt64(info[1]);
char *ptr = Buffer::Data(buf.As<Object>()) + offset;
size_t size = info[2]->Uint32Value();

Expand All @@ -263,9 +262,7 @@ NAN_METHOD(ReadPointer) {
}

char *val = *reinterpret_cast<char **>(ptr);
void *user_data = NULL;
Local<Object> rtn_buf = Nan::NewBuffer(val, size, read_pointer_cb, user_data).ToLocalChecked();
info.GetReturnValue().Set(rtn_buf);
info.GetReturnValue().Set(WrapPointer(val, size));
}

/*
Expand All @@ -289,7 +286,7 @@ NAN_METHOD(WritePointer) {
return Nan::ThrowTypeError("writePointer: Buffer instance expected as third argument");
}

int64_t offset = info[1]->IntegerValue();
int64_t offset = GetInt64(info[1]);
char *ptr = Buffer::Data(buf.As<Object>()) + offset;

if (input->IsNull()) {
Expand All @@ -316,7 +313,7 @@ NAN_METHOD(ReadInt64) {
return Nan::ThrowTypeError("readInt64: Buffer instance expected");
}

int64_t offset = info[1]->IntegerValue();
int64_t offset = GetInt64(info[1]);
char *ptr = Buffer::Data(buf.As<Object>()) + offset;

if (ptr == NULL) {
Expand Down Expand Up @@ -355,13 +352,13 @@ NAN_METHOD(WriteInt64) {
return Nan::ThrowTypeError("writeInt64: Buffer instance expected");
}

int64_t offset = info[1]->IntegerValue();
int64_t offset = GetInt64(info[1]);
char *ptr = Buffer::Data(buf.As<Object>()) + offset;

Local<Value> in = info[2];
int64_t val;
if (in->IsNumber()) {
val = in->IntegerValue();
val = GetInt64(in);
} else if (in->IsString()) {
// Have to do this because strtoll doesn't set errno to 0 on success :(
errno = 0;
Expand Down Expand Up @@ -391,7 +388,7 @@ NAN_METHOD(ReadUInt64) {
return Nan::ThrowTypeError("readUInt64: Buffer instance expected");
}

int64_t offset = info[1]->IntegerValue();
int64_t offset = GetInt64(info[1]);;
char *ptr = Buffer::Data(buf.As<Object>()) + offset;

if (ptr == NULL) {
Expand Down Expand Up @@ -430,13 +427,13 @@ NAN_METHOD(WriteUInt64) {
return Nan::ThrowTypeError("writeUInt64: Buffer instance expected");
}

int64_t offset = info[1]->IntegerValue();
int64_t offset = GetInt64(info[1]);;
char *ptr = Buffer::Data(buf.As<Object>()) + offset;

Local<Value> in = info[2];
uint64_t val;
if (in->IsNumber()) {
val = in->IntegerValue();
val = GetInt64(in);;
} else if (in->IsString()) {
// Have to do this because strtoull doesn't set errno to 0 on success :(
errno = 0;
Expand Down Expand Up @@ -468,7 +465,7 @@ NAN_METHOD(ReadCString) {
return Nan::ThrowTypeError("readCString: Buffer instance expected");
}

int64_t offset = info[1]->IntegerValue();
int64_t offset = GetInt64(info[1]);
char *ptr = Buffer::Data(buf.As<Object>()) + offset;

if (ptr == NULL) {
Expand All @@ -495,7 +492,7 @@ NAN_METHOD(ReinterpretBuffer) {
return Nan::ThrowTypeError("reinterpret: Buffer instance expected");
}

int64_t offset = info[2]->IntegerValue();
int64_t offset = GetInt64(info[2]);
char *ptr = Buffer::Data(buf.As<Object>()) + offset;

if (ptr == NULL) {
Expand All @@ -504,8 +501,7 @@ NAN_METHOD(ReinterpretBuffer) {

size_t size = info[1]->Uint32Value();

Local<Object> rtn = Nan::NewBuffer(ptr, size, read_pointer_cb, NULL).ToLocalChecked();
info.GetReturnValue().Set(rtn);
info.GetReturnValue().Set(WrapPointer(ptr, size));
}

/*
Expand All @@ -525,7 +521,7 @@ NAN_METHOD(ReinterpretBufferUntilZeros) {
return Nan::ThrowTypeError("reinterpretUntilZeros: Buffer instance expected");
}

int64_t offset = info[2]->IntegerValue();
int64_t offset = GetInt64(info[2]);
char *ptr = Buffer::Data(buf.As<Object>()) + offset;

if (ptr == NULL) {
Expand All @@ -550,9 +546,7 @@ NAN_METHOD(ReinterpretBufferUntilZeros) {
}
}

Local<Object> rtn = Nan::NewBuffer(ptr, size, read_pointer_cb, NULL).ToLocalChecked();

info.GetReturnValue().Set(rtn);
info.GetReturnValue().Set(WrapPointer(ptr, size));
}


Expand Down Expand Up @@ -592,7 +586,7 @@ NAN_MODULE_INIT(init) {
SET_SIZEOF(pointer, char *);
SET_SIZEOF(size_t, size_t);
// size of a Persistent handle to a JS object
SET_SIZEOF(Object, Persistent<Object>);
SET_SIZEOF(Object, Nan::Persistent<Object>);

// "alignof" map
Local<Object> amap = Nan::New<v8::Object>();
Expand Down Expand Up @@ -622,7 +616,7 @@ NAN_MODULE_INIT(init) {
SET_ALIGNOF(ulonglong, unsigned long long);
SET_ALIGNOF(pointer, char *);
SET_ALIGNOF(size_t, size_t);
SET_ALIGNOF(Object, Persistent<Object>);
SET_ALIGNOF(Object, Nan::Persistent<Object>);

// exports
target->Set(Nan::New<v8::String>("sizeof").ToLocalChecked(), smap);
Expand Down
24 changes: 24 additions & 0 deletions test/iojs3issue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
var assert = require('assert')
var ref = require('../')

// This will check if the new Buffer implementation behaves like the pre io.js 3.0 one did:
describe('iojs3issue', function () {
it('should not crash', function() {
for (var i = 0; i < 10; i++) {
gc()
var buf = new Buffer(8)
buf.fill(0)
var buf2 = ref.ref(buf)
var buf3 = ref.deref(buf2)
}
})
it('should not crash too', function() {
for (var i = 0; i < 10; i++) {
gc()
var buf = new Buffer(7)
buf.fill(0)
var buf2 = ref.ref(buf)
var buf3 = ref.deref(buf2)
}
})
})

0 comments on commit 31fe46b

Please sign in to comment.