Skip to content
This repository was archived by the owner on Apr 22, 2023. It is now read-only.

Commit 0afed52

Browse files
committed
initial blobs
1 parent 359d017 commit 0afed52

File tree

4 files changed

+309
-0
lines changed

4 files changed

+309
-0
lines changed

src/node.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <errno.h>
1111
#include <dlfcn.h> /* dlopen(), dlsym() */
1212

13+
#include <node_blob.h>
1314
#include <node_events.h>
1415
#include <node_dns.h>
1516
#include <node_net.h>
@@ -847,6 +848,7 @@ static Local<Object> Load(int argc, char *argv[]) {
847848

848849

849850
// Initialize the C++ modules..................filename of module
851+
InitBlob(process); // stdio.cc
850852
Stdio::Initialize(process); // stdio.cc
851853
Timer::Initialize(process); // timer.cc
852854
SignalHandler::Initialize(process); // signal_handler.cc

src/node_blob.cc

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
#include <assert.h>
2+
#include <stdlib.h> // malloc, free
3+
#include <v8.h>
4+
#include <node.h>
5+
6+
namespace node {
7+
8+
using namespace v8;
9+
10+
#define MIN(a,b) ((a) < (b) ? (a) : (b))
11+
12+
#define SLICE_ARGS(start_arg, end_arg) \
13+
if (!start_arg->IsInt32() || !end_arg->IsInt32()) { \
14+
return ThrowException(Exception::TypeError( \
15+
String::New("Bad argument."))); \
16+
} \
17+
int32_t start = start_arg->Int32Value(); \
18+
int32_t end = end_arg->Int32Value(); \
19+
if (start < 0 || end < 0) { \
20+
return ThrowException(Exception::TypeError( \
21+
String::New("Bad argument."))); \
22+
}
23+
24+
static Persistent<String> length_symbol;
25+
static Persistent<FunctionTemplate> constructor_template;
26+
27+
/* A blob is a chunk of memory stored outside the V8 heap mirrored by an
28+
* object in javascript. The object is not totally opaque, one can access
29+
* individual bytes with [] and one can slice the blob into substrings or
30+
* subblobs without copying memory.
31+
*
32+
* blob.asciiSlide(0, 3) // return an ascii encoded string - no memory iscopied
33+
* blob.slice(0, 3) // returns another blob - no memory is copied
34+
*
35+
* Interally, each javascript blob object is backed by a "struct blob" object.
36+
* These "struct blob" objects are either the root object (in the case that
37+
* blob->root == NULL) or slice objects (in which case blob->root != NULL).
38+
* The root blob is only GCed once all it's slices are GCed.
39+
*/
40+
41+
struct blob {
42+
Persistent<Object> handle; // both
43+
bool weak; // both
44+
struct blob *root; // both (NULL for root)
45+
size_t offset; // both (0 for root)
46+
size_t length; // both
47+
unsigned int refs; // root only
48+
char bytes[1]; // root only
49+
};
50+
51+
52+
static inline struct blob* blob_root(blob *blob) {
53+
return blob->root ? blob->root : blob;
54+
}
55+
56+
/* Determines the absolute position for a relative offset */
57+
static inline size_t blob_abs_off(blob *blob, size_t off) {
58+
struct blob *root = blob_root(blob);
59+
off += root->offset;
60+
return MIN(root->length, off);
61+
}
62+
63+
64+
static inline void blob_ref(struct blob *blob) {
65+
assert(blob->root == NULL);
66+
blob->refs++;
67+
}
68+
69+
70+
static inline void blob_unref(struct blob *blob) {
71+
assert(blob->root == NULL);
72+
assert(blob->refs > 0);
73+
blob->refs--;
74+
if (blob->refs == 0 && blob->weak) free(blob);
75+
}
76+
77+
78+
static inline struct blob* Unwrap(Handle<Value> val) {
79+
assert(val->IsObject());
80+
HandleScope scope;
81+
Local<Object> obj = val->ToObject();
82+
assert(obj->InternalFieldCount() == 1);
83+
Local<External> ext = Local<External>::Cast(obj->GetInternalField(0));
84+
return static_cast<struct blob*>(ext->Value());
85+
}
86+
87+
88+
static void RootWeakCallback(Persistent<Value> value, void *data)
89+
{
90+
struct blob *blob = static_cast<struct blob*>(data);
91+
assert(blob->root == NULL); // this is the root
92+
assert(value == blob->handle);
93+
blob->handle.Dispose();
94+
if (blob->refs) {
95+
blob->weak = true;
96+
} else {
97+
free(blob);
98+
}
99+
}
100+
101+
102+
static void SliceWeakCallback(Persistent<Value> value, void *data)
103+
{
104+
struct blob *blob = static_cast<struct blob*>(data);
105+
assert(blob->root != NULL); // this is a slice
106+
assert(value == blob->handle);
107+
blob->handle.Dispose();
108+
blob_unref(blob->root);
109+
}
110+
111+
112+
static Handle<Value> Constructor(const Arguments &args) {
113+
HandleScope scope;
114+
115+
size_t length;
116+
struct blob *blob;
117+
118+
if (constructor_template->HasInstance(args[0])) {
119+
// slice slice
120+
SLICE_ARGS(args[1], args[2])
121+
122+
struct blob *parent = Unwrap(args[0]);
123+
124+
size_t start_abs = blob_abs_off(parent, start);
125+
size_t end_abs = blob_abs_off(parent, end);
126+
assert(start_abs <= end_abs);
127+
length = end_abs - start_abs;
128+
129+
void *d = malloc(sizeof(struct blob));
130+
131+
if (!d) {
132+
V8::LowMemoryNotification();
133+
return ThrowException(Exception::Error(
134+
String::New("Could not allocate enough memory")));
135+
136+
}
137+
138+
blob = static_cast<struct blob*>(d);
139+
140+
blob->length = length;
141+
blob->offset = start_abs;
142+
blob->weak = false;
143+
blob->refs = 0;
144+
blob->root = blob_root(parent);
145+
blob->handle = Persistent<Object>::New(args.This());
146+
blob->handle.MakeWeak(blob, SliceWeakCallback);
147+
148+
blob_ref(blob->root);
149+
} else {
150+
// Root slice
151+
152+
length = args[0]->Uint32Value();
153+
154+
if (length < 1) {
155+
return ThrowException(Exception::TypeError(
156+
String::New("Bad argument. Length must be positive")));
157+
}
158+
159+
// TODO alignment. modify the length?
160+
void *d = malloc(sizeof(struct blob) + length - 1);
161+
162+
if (!d) {
163+
V8::LowMemoryNotification();
164+
return ThrowException(Exception::Error(
165+
String::New("Could not allocate enough memory")));
166+
}
167+
168+
blob = static_cast<struct blob*>(d);
169+
170+
blob->offset = 0;
171+
blob->length = length;
172+
blob->weak = false;
173+
blob->refs = 0;
174+
blob->root = NULL;
175+
blob->handle = Persistent<Object>::New(args.This());
176+
blob->handle.MakeWeak(blob, RootWeakCallback);
177+
}
178+
179+
args.This()->SetInternalField(0, v8::External::New(blob));
180+
181+
struct blob *root = blob_root(blob);
182+
183+
args.This()->
184+
SetIndexedPropertiesToExternalArrayData(&root->bytes + blob->offset,
185+
kExternalUnsignedByteArray,
186+
length);
187+
188+
args.This()->Set(length_symbol, Integer::New(length));
189+
190+
return args.This();
191+
}
192+
193+
194+
class AsciiSliceExt: public String::ExternalAsciiStringResource {
195+
public:
196+
197+
AsciiSliceExt(struct blob *root, size_t start, size_t end)
198+
{
199+
data_ = root->bytes + start;
200+
len_ = end - start;
201+
root_ = root;
202+
blob_ref(root_);
203+
}
204+
205+
~AsciiSliceExt() {
206+
blob_unref(root_);
207+
}
208+
209+
const char* data() const {
210+
return data_;
211+
}
212+
213+
size_t length() const {
214+
return len_;
215+
}
216+
217+
private:
218+
const char *data_;
219+
size_t len_;
220+
struct blob *root_;
221+
};
222+
223+
static Handle<Value> AsciiSlice(const Arguments &args) {
224+
HandleScope scope;
225+
226+
SLICE_ARGS(args[0], args[1])
227+
228+
assert(args.This()->InternalFieldCount() == 1);
229+
struct blob *parent = Unwrap(args.This());
230+
231+
size_t start_abs = blob_abs_off(parent, start);
232+
size_t end_abs = blob_abs_off(parent, end);
233+
234+
assert(start_abs <= end_abs);
235+
236+
AsciiSliceExt *s = new AsciiSliceExt(blob_root(parent), start_abs, end_abs);
237+
Local<String> string = String::NewExternal(s);
238+
239+
struct blob *root = blob_root(parent);
240+
assert(root->refs > 0);
241+
242+
return scope.Close(string);
243+
}
244+
245+
static Handle<Value> Utf8Slice(const Arguments &args) {
246+
HandleScope scope;
247+
248+
SLICE_ARGS(args[0], args[1])
249+
250+
struct blob *parent = Unwrap(args.This());
251+
size_t start_abs = blob_abs_off(parent, start);
252+
size_t end_abs = blob_abs_off(parent, end);
253+
assert(start_abs <= end_abs);
254+
255+
struct blob *root = blob_root(parent);
256+
257+
Local<String> string =
258+
String::New(reinterpret_cast<const char*>(&root->bytes + start_abs),
259+
end_abs - start_abs);
260+
return scope.Close(string);
261+
}
262+
263+
static Handle<Value> Slice(const Arguments &args) {
264+
HandleScope scope;
265+
266+
Local<Value> argv[3] = { args.This(), args[0], args[1] };
267+
268+
Local<Object> slice =
269+
constructor_template->GetFunction()->NewInstance(3, argv);
270+
271+
return scope.Close(slice);
272+
}
273+
274+
void InitBlob(Handle<Object> target) {
275+
HandleScope scope;
276+
277+
length_symbol = Persistent<String>::New(String::NewSymbol("length"));
278+
279+
Local<FunctionTemplate> t = FunctionTemplate::New(Constructor);
280+
constructor_template = Persistent<FunctionTemplate>::New(t);
281+
constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
282+
constructor_template->SetClassName(String::NewSymbol("Blob"));
283+
284+
// copy free
285+
NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiSlice", AsciiSlice);
286+
NODE_SET_PROTOTYPE_METHOD(constructor_template, "slice", Slice);
287+
// TODO NODE_SET_PROTOTYPE_METHOD(t, "utf16Slice", Utf16Slice);
288+
// copy
289+
NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Slice", Utf8Slice);
290+
291+
target->Set(String::NewSymbol("Blob"), constructor_template->GetFunction());
292+
}
293+
294+
} // namespace node

src/node_blob.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#ifndef NODE_BLOB
2+
#define NODE_BLOB
3+
4+
#include <v8.h>
5+
6+
namespace node {
7+
8+
void InitBlob(v8::Handle<v8::Object> target);
9+
10+
}
11+
12+
#endif // NODE_BLOB

wscript

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ def build(bld):
322322
node.target = "node"
323323
node.source = """
324324
src/node.cc
325+
src/node_blob.cc
325326
src/node_child_process.cc
326327
src/node_constants.cc
327328
src/node_dns.cc

0 commit comments

Comments
 (0)