-
Notifications
You must be signed in to change notification settings - Fork 414
/
ffi_tests.cc
206 lines (161 loc) · 4.76 KB
/
ffi_tests.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#include <stdlib.h>
#include "v8.h"
#include "node.h"
#include "node_buffer.h"
using namespace v8;
using namespace node;
namespace {
/*
* Test struct definition used in the test harness functions below.
*/
typedef struct box {
int width;
int height;
} _box;
/*
* Accepts a struct by value, and returns a struct by value.
*/
box double_box(box input) {
box rtn;
// modify the input box, ensure on the JS side that it's not altered
input.width *= 2;
input.height *= 2;
rtn.width = input.width;
rtn.height = input.height;
return rtn;
}
/*
* Accepts a box struct pointer, and returns a struct by value.
*/
box double_box_ptr(box *input) {
box rtn;
// modify the input box, ensure on the JS side that IT IS altered
input->width *= 2;
input->height *= 2;
rtn.width = input->width;
rtn.height = input->height;
return rtn;
}
/*
* Accepts a struct by value, and returns an int.
*/
int area_box(box input) {
return input.width * input.height;
}
/*
* Accepts a box pointer and returns an int.
*/
int area_box_ptr(box *input) {
return input->width * input->height;
}
/*
* Creates a box and returns it by value.
*/
box create_box(int width, int height) {
box rtn = { width, height };
return rtn;
}
/*
* Creates a box that has the sum of the width and height for its own values.
*/
box add_boxes(box boxes[], int num) {
box rtn = { 0, 0 };
box cur;
for (int i = 0; i < num; i++) {
cur = boxes[i];
rtn.width += cur.width;
rtn.height += cur.height;
}
return rtn;
}
/*
* Hard-coded `strtoul` binding, for the benchmarks.
*
* args[0] - the string number to convert to a real Number
* args[1] - a "buffer" instance to write into (the "endptr")
* args[2] - the base (0 means autodetect)
*/
Handle<Value> Strtoul(const Arguments &args) {
HandleScope scope;
char buf[128];
int base;
char **endptr;
args[0]->ToString()->WriteUtf8(buf);
Local<Value> endptr_arg = args[0];
endptr = (char **)Buffer::Data(endptr_arg.As<Object>());
base = args[2]->Int32Value();
unsigned long val = strtoul(buf, endptr, base);
return scope.Close(Integer::NewFromUnsigned(val));
}
// experiments for #72
typedef void (*cb)(void);
static cb callback = NULL;
Handle<Value> SetCb(const Arguments &args) {
HandleScope scope;
char *buf = Buffer::Data(args[0].As<Object>());
callback = (cb)buf;
return scope.Close(Undefined());
}
Handle<Value> CallCb(const Arguments &args) {
if (callback == NULL) {
return ThrowException(Exception::Error(String::New("you must call \"set_cb()\" first")));
} else {
callback();
}
return Undefined();
}
void AsyncCbCall(uv_work_t *req) {
callback();
}
void FinishAsyncCbCall(uv_work_t *req) {
// nothing
delete req;
}
Handle<Value> CallCbAsync(const Arguments &args) {
if (callback == NULL) {
return ThrowException(Exception::Error(String::New("you must call \"set_cb()\" first")));
} else {
uv_work_t *req = new uv_work_t;
uv_queue_work(uv_default_loop(), req, AsyncCbCall, FinishAsyncCbCall);
}
return Undefined();
}
void wrap_pointer_cb(char *data, void *hint) {
//fprintf(stderr, "wrap_pointer_cb\n");
}
Handle<Object> WrapPointer(char *ptr) {
void *user_data = NULL;
size_t length = 0;
Buffer *buf = Buffer::New(ptr, length, wrap_pointer_cb, user_data);
return buf->handle_;
}
void Initialize(Handle<Object> target) {
HandleScope scope;
#if WIN32
// initialize "floating point support" on Windows?!?!
// (this is some serious bullshit...)
// http://support.microsoft.com/kb/37507
float x = 2.3f;
#endif
// atoi and abs here for testing purposes
target->Set(String::NewSymbol("atoi"), WrapPointer((char *)atoi));
// Windows has multiple `abs` signatures, so we need to manually disambiguate
int (*absPtr)(int)(abs);
target->Set(String::NewSymbol("abs"), WrapPointer((char *)absPtr));
// sprintf pointer; used in the varadic tests
target->Set(String::NewSymbol("sprintf"), WrapPointer((char *)sprintf));
// hard-coded `strtoul` binding, for the benchmarks
NODE_SET_METHOD(target, "strtoul", Strtoul);
NODE_SET_METHOD(target, "set_cb", SetCb);
NODE_SET_METHOD(target, "call_cb", CallCb);
NODE_SET_METHOD(target, "call_cb_async", CallCbAsync);
// also need to test these custom functions
target->Set(String::NewSymbol("double_box"), WrapPointer((char *)double_box));
target->Set(String::NewSymbol("double_box_ptr"), WrapPointer((char *)double_box_ptr));
target->Set(String::NewSymbol("area_box"), WrapPointer((char *)area_box));
target->Set(String::NewSymbol("area_box_ptr"), WrapPointer((char *)area_box_ptr));
target->Set(String::NewSymbol("create_box"), WrapPointer((char *)create_box));
target->Set(String::NewSymbol("add_boxes"), WrapPointer((char *)add_boxes));
}
} // anonymous namespace
NODE_MODULE(ffi_tests, Initialize);