Skip to content

Commit 203f021

Browse files
committed
Backport C-API needed for OpenSSL C-ext 2.x.
1 parent a97b41b commit 203f021

File tree

8 files changed

+425
-20
lines changed

8 files changed

+425
-20
lines changed

vm/builtin/data.cpp

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ namespace rubinius {
3333
RDataShadow* rdata = reinterpret_cast<RDataShadow*>(handle->as_rdata(0));
3434

3535
rdata->data = data_ptr;
36-
rdata->dmark = mark;
37-
rdata->dfree = free;
36+
rdata->d.untyped.dmark = mark;
37+
rdata->d.untyped.dfree = free;
3838

3939
data->internal_ = rdata;
4040

@@ -47,16 +47,60 @@ namespace rubinius {
4747
return data;
4848
}
4949

50+
Data* Data::create_typed(STATE, void* data_ptr, const struct rb_data_type_struct_shadow* type) {
51+
Data* data;
52+
53+
data = state->new_object<Data>(G(data));
54+
data->freed_ = false;
55+
56+
// Data is just a heap alias for the handle, so go ahead and create
57+
// the handle and populate it as an RData now.
58+
capi::Handle* handle = data->handle(state);
59+
60+
assert(!handle && "can't already have a handle, it's brand new!");
61+
62+
handle = state->memory()->add_capi_handle(state, data);
63+
64+
// Don't call ->ref() on handle! We don't want the handle to keep the object
65+
// alive by default. The handle needs to have the lifetime of the object.
66+
67+
RDataShadow* rdata = reinterpret_cast<RDataShadow*>(handle->as_rtypeddata(0));
68+
69+
rdata->data = data_ptr;
70+
rdata->d.typed.typed = 1;
71+
rdata->d.typed.type = type;
72+
73+
data->internal_ = rdata;
74+
75+
if(type->function.dmark || type->function.dfree) {
76+
state->memory()->needs_finalization(data, (FinalizerFunction)&Data::finalize);
77+
}
78+
79+
state->vm()->metrics().m.ruby_metrics.memory_data_objects_total++;
80+
81+
return data;
82+
}
83+
5084
void* Data::data() {
5185
return rdata()->data;
5286
}
5387

5488
Data::FreeFunctor Data::free() {
55-
return rdata()->dfree;
89+
RDataShadow* data = rdata();
90+
if(typed()) {
91+
return data->d.typed.type->function.dfree;
92+
} else {
93+
return data->d.untyped.dfree;
94+
}
5695
}
5796

5897
Data::MarkFunctor Data::mark() {
59-
return rdata()->dmark;
98+
RDataShadow* data = rdata();
99+
if(typed()) {
100+
return data->d.typed.type->function.dmark;
101+
} else {
102+
return data->d.untyped.dmark;
103+
}
60104
}
61105

62106
void Data::finalize(STATE, Data* data) {
@@ -126,4 +170,5 @@ namespace rubinius {
126170
capi::set_current_mark(cur);
127171
}
128172
}
173+
129174
}

vm/builtin/data.hpp

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,40 @@ namespace rubinius {
77
// Copied from here because you can't include capi/include/ruby.h into
88
// our C++ files.
99

10-
struct RDataShadow {
10+
struct rb_data_type_struct_shadow {
11+
const char *wrap_struct_name;
12+
struct {
13+
void (*dmark)(void*);
14+
void (*dfree)(void*);
15+
size_t (*dsize)(const void *);
16+
void *reserved[2]; /* For future extension.
17+
This array *must* be filled with ZERO. */
18+
} function;
19+
const struct rb_data_type_struct_shadow* parent;
20+
void *data; /* This area can be used for any purpose
21+
by a programmer who define the type. */
22+
};
23+
24+
// This union crazyness is needed because these should be compatible
25+
// for the data pointer. It is valid behavior to use DATA_PTR on both
26+
// typed and untyped and get a valid result back.
27+
// MRI constructs this differently, but this approach allows us to
28+
// use this in a slightly more type safe and explicit way.
29+
struct RUntypedDataShadow {
1130
void (*dmark)(void*);
1231
void (*dfree)(void*);
32+
};
33+
34+
struct RTypedDataShadow {
35+
const struct rb_data_type_struct_shadow* type;
36+
native_int typed;
37+
};
38+
39+
struct RDataShadow {
40+
union {
41+
RUntypedDataShadow untyped;
42+
RTypedDataShadow typed;
43+
} d;
1344
void *data;
1445
};
1546

@@ -36,6 +67,9 @@ namespace rubinius {
3667
/** New Data instance. */
3768
static Data* create(STATE, void* data, MarkFunctor mark, FreeFunctor free);
3869

70+
/** New typed Data instance. */
71+
static Data* create_typed(STATE, void* data, const struct rb_data_type_struct_shadow* type);
72+
3973
static void finalize(STATE, Data* data);
4074

4175
bool freed_p() const {
@@ -54,6 +88,17 @@ namespace rubinius {
5488
return internal_;
5589
}
5690

91+
bool typed() {
92+
return rdata()->d.typed.typed == 1;
93+
}
94+
95+
const struct rb_data_type_struct_shadow* data_type() {
96+
if(typed()) {
97+
return rdata()->d.typed.type;
98+
}
99+
return NULL;
100+
}
101+
57102
void* data();
58103
FreeFunctor free();
59104
MarkFunctor mark();

vm/capi/data.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,29 @@ namespace rubinius {
3333
return rdata;
3434
}
3535
}
36+
37+
RTypedData* Handle::as_rtypeddata(NativeMethodEnvironment* env) {
38+
Data* data = c_as<Data>(object_);
39+
40+
if(data->freed_p()) {
41+
rb_raise(rb_eArgError, "Data object has already been freed");
42+
}
43+
44+
if(type_ == cRData) {
45+
return as_.rtypeddata;
46+
} else {
47+
type_ = cRData;
48+
49+
RTypedData* rtypeddata = new RTypedData;
50+
rtypeddata->data = 0;
51+
rtypeddata->type = 0;
52+
rtypeddata->typed_flag = 1;
53+
54+
as_.rtypeddata = rtypeddata;
55+
56+
return rtypeddata;
57+
}
58+
}
3659
}
3760
}
3861

@@ -60,4 +83,58 @@ extern "C" {
6083

6184
return env->get_handle(data);
6285
}
86+
87+
struct RTypedData* capi_rtypeddata_struct(VALUE data_handle) {
88+
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
89+
90+
Handle* handle = Handle::from(data_handle);
91+
env->check_tracked_handle(handle, false);
92+
93+
return handle->as_rtypeddata(env);
94+
}
95+
96+
VALUE rb_data_typed_object_alloc(VALUE klass, void* ptr, const rb_data_type_t* type) {
97+
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
98+
99+
if(!klass) klass = rb_cObject;
100+
101+
Class* data_klass = c_as<Class>(env->get_object(klass));
102+
103+
Data* data = Data::create_typed(env->state(), ptr, reinterpret_cast<const struct rb_data_type_struct_shadow*>(type));
104+
105+
data->klass(env->state(), data_klass);
106+
107+
return env->get_handle(data);
108+
}
109+
110+
int rb_typeddata_inherited_p(const rb_data_type_t *child, const rb_data_type_t *parent) {
111+
while (child) {
112+
if (child == parent) return 1;
113+
child = child->parent;
114+
}
115+
return 0;
116+
}
117+
118+
void* rb_check_typeddata(VALUE obj, const rb_data_type_t* data_type) {
119+
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
120+
const char* mesg = "wrong argument type %s (expected %s)";
121+
Data* data = c_as<Data>(env->get_object(obj));
122+
if(!data->typed()) {
123+
rb_raise(rb_eTypeError, mesg, rb_obj_classname(obj), data_type->wrap_struct_name);
124+
}
125+
126+
const rb_data_type_t* other_type = reinterpret_cast<const rb_data_type_t*>(data->data_type());
127+
128+
if (!rb_typeddata_inherited_p(other_type, data_type)) {
129+
rb_raise(rb_eTypeError, mesg, other_type->wrap_struct_name, data_type->wrap_struct_name);
130+
}
131+
return data->data();
132+
}
133+
134+
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type) {
135+
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
136+
Data* data = try_as<Data>(env->get_object(obj));
137+
if(!data || !data->typed()) return 0;
138+
return rb_typeddata_inherited_p(RTYPEDDATA_TYPE(obj), data_type);
139+
}
63140
}

vm/capi/file.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,38 @@ extern "C" {
2828
return Handle::from(file)->as_rfile(env);
2929
}
3030

31+
int rb_cloexec_dup(int fd) {
32+
return fcntl(fd, F_DUPFD_CLOEXEC, 3);
33+
}
34+
3135
VALUE rb_file_open(const char* name, const char* mode) {
3236
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
3337
VALUE n = env->get_handle(String::create(env->state(), name));
3438
VALUE m = env->get_handle(String::create(env->state(), mode));
3539

3640
return rb_funcall(rb_cFile, rb_intern("open"), 2, n, m);
3741
}
42+
43+
FILE * rb_io_stdio_file(rb_io_t *fptr) {
44+
return fptr->f;
45+
}
46+
47+
VALUE rb_file_path_value(volatile VALUE* obj) {
48+
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
49+
STATE = env->state();
50+
51+
if(!kind_of<String>(env->get_object(*obj))) {
52+
*obj = rb_funcall(env->get_handle(G(type)), rb_intern("coerce_to_path"), 1, *obj);
53+
}
54+
55+
return *obj;
56+
}
57+
58+
VALUE rb_file_open_str(VALUE name, const char* mode) {
59+
NativeMethodEnvironment* env = NativeMethodEnvironment::get();
60+
VALUE m = env->get_handle(String::create(env->state(), mode));
61+
62+
FilePathValue(name);
63+
return rb_funcall(rb_cFile, rb_intern("open"), 2, name, m);
64+
}
3865
}

vm/capi/handle.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
#include "detection.hpp"
55

6-
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070
6+
#if defined(__APPLE__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070
77
#ifndef RBX_HAVE_TR1_HASH
88
#include "missing/leopard_hashtable.hpp"
99
#endif
@@ -23,6 +23,7 @@
2323
struct RArray;
2424
struct RString;
2525
struct RData;
26+
struct RTypedData;
2627
struct RFloat;
2728
struct RIO;
2829
struct RFile;
@@ -58,6 +59,7 @@ namespace rubinius {
5859
RArray* rarray;
5960
RString* rstring;
6061
RData* rdata;
62+
RTypedData* rtypeddata;
6163
RFloat* rfloat;
6264
RIO* rio;
6365
RFile* rfile;
@@ -191,6 +193,7 @@ namespace rubinius {
191193
}
192194

193195
RData* as_rdata(NativeMethodEnvironment* env);
196+
RTypedData* as_rtypeddata(NativeMethodEnvironment* env);
194197
RArray* as_rarray(NativeMethodEnvironment* env);
195198
RString* as_rstring(NativeMethodEnvironment* env, int cache_level);
196199
RFloat* as_rfloat(NativeMethodEnvironment* env);

vm/capi/hash.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,16 @@ extern "C" {
4343
}
4444

4545
VALUE rb_hash_lookup(VALUE self, VALUE key) {
46-
VALUE entry = capi_fast_call(self, rb_intern("find_item"), 1, key);
46+
return rb_hash_lookup2(self, key, Qnil);
47+
}
48+
49+
VALUE rb_hash_lookup2(VALUE hash, VALUE key, VALUE def) {
50+
VALUE entry = capi_fast_call(hash, rb_intern("find_item"), 1, key);
51+
4752
if(entry != Qnil) {
4853
return capi_fast_call(entry, rb_intern("value"), 0);
4954
} else {
50-
return Qnil;
55+
return def;
5156
}
5257
}
5358

@@ -83,4 +88,10 @@ extern "C" {
8388
}
8489
}
8590
}
91+
92+
VALUE rb_hash_set_ifnone(VALUE hash, VALUE def) {
93+
capi_fast_call(hash, rb_intern("default="), 1, def);
94+
95+
return hash;
96+
}
8697
}

vm/capi/symbol.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,8 @@ extern "C" {
4040
Object* p = reinterpret_cast<Symbol*>(sym)->is_cvar_p(env->state());
4141
return CBOOL(p) ? Qtrue : Qfalse;
4242
}
43+
44+
VALUE rb_sym2str(VALUE sym) {
45+
return rb_id2str(SYM2ID(sym));
46+
}
4347
}

0 commit comments

Comments
 (0)