Skip to content
This repository has been archived by the owner on Aug 18, 2018. It is now read-only.

Commit

Permalink
Cautiously edge toward a slippery slope, by adding extra cleanup call…
Browse files Browse the repository at this point in the history
…backs.
  • Loading branch information
matthewd committed Apr 28, 2008
1 parent 1d2b61f commit ce00ab6
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 49 deletions.
12 changes: 6 additions & 6 deletions ext/spidermonkey/conversions.c
Expand Up @@ -10,7 +10,7 @@ static JSBool convert_float_or_bignum_to_js(OurContext* context, VALUE float_or_

static JSBool convert_symbol_to_js(OurContext* context, VALUE symbol, jsval* retval)
{
PREPARE_JROOTS(context, "convert_symbol_to_js", 2);
PREPARE_JROOTS(context, 2, 0);

VALUE to_s = rb_funcall(symbol, rb_intern("to_s"), 0);
jsval name = STRING_TO_JSVAL(JS_NewStringCopyN(context->js, StringValuePtr(to_s), (unsigned) StringValueLen(to_s)));
Expand Down Expand Up @@ -113,7 +113,7 @@ JSBool convert_to_js(OurContext* context, VALUE ruby, jsval* retval)

VALUE convert_jsstring_to_ruby(OurContext* context, JSString* str)
{
PREPARE_RUBY_JROOTS(context, "convert_jsstring_to_ruby", 1);
PREPARE_RUBY_JROOTS(context, 1, 0);
JROOT(str);
char* bytes = JS_GetStringBytes(str);
assert(bytes);
Expand All @@ -123,7 +123,7 @@ VALUE convert_jsstring_to_ruby(OurContext* context, JSString* str)

static VALUE convert_regexp_to_ruby(OurContext* context, jsval regexp)
{
PREPARE_RUBY_JROOTS(context, "convert_regexp_to_ruby", 1);
PREPARE_RUBY_JROOTS(context, 1, 0);
JROOT(regexp);
JSRegExp* re = (JSRegExp*)JS_GetPrivate(context->js, JSVAL_TO_OBJECT(regexp));

Expand All @@ -136,7 +136,7 @@ static VALUE convert_regexp_to_ruby(OurContext* context, jsval regexp)

static bool js_value_is_regexp(OurContext* context, jsval maybe_regexp)
{
PREPARE_RUBY_JROOTS(context, "js_value_is_regexp", 1);
PREPARE_RUBY_JROOTS(context, 1, 0);
JROOT(maybe_regexp);
JSBool result = JS_InstanceOf(context->js, JSVAL_TO_OBJECT(maybe_regexp), &js_RegExpClass, NULL);
JRETURN_RUBY(result ? true : false);
Expand All @@ -146,7 +146,7 @@ static bool js_value_is_symbol(OurContext* context, jsval maybe_symbol)
{
jsval nsJohnson, cSymbol;

PREPARE_RUBY_JROOTS(context, "js_value_is_symbol", 3);
PREPARE_RUBY_JROOTS(context, 3, 0);
JROOT(maybe_symbol);

JCHECK(JS_GetProperty(context->js, context->global, "Johnson", &nsJohnson));
Expand All @@ -169,7 +169,7 @@ VALUE convert_to_ruby(OurContext* context, jsval js)
{
if (JSVAL_NULL == js) return Qnil;

PREPARE_RUBY_JROOTS(context, "convert_to_ruby", 1);
PREPARE_RUBY_JROOTS(context, 1, 0);

switch (JS_TypeOfValue(context->js, js))
{
Expand Down
2 changes: 1 addition & 1 deletion ext/spidermonkey/extensions.c
Expand Up @@ -14,7 +14,7 @@ define_property(JSContext *js_context, JSObject* UNUSED(obj), uintN argc, jsval

VALUE init_spidermonkey_extensions(OurContext* context, VALUE self)
{
PREPARE_RUBY_JROOTS(context, "init_spidermonkey_extensions", 1);
PREPARE_RUBY_JROOTS(context, 1, 0);

jsval Object;
JCHECK(JS_GetProperty(context->js, context->global, "Object", &Object));
Expand Down
48 changes: 31 additions & 17 deletions ext/spidermonkey/jroot.h
Expand Up @@ -12,44 +12,55 @@
_context; \
})

#define _PREPARE_JROOTS(rb, context, name, maxcount) \
#define _PREPARE_JROOTS(rb, context, rootcount, cleancount) \
const bool _jroot_ruby = (rb); \
const char* const MAYBE_UNUSED(_jroot_basename) = (name); \
int _jroot_avail = (maxcount); \
void* _jroot_map[_jroot_avail]; \
int _jroot_roots = (rootcount); \
void* _jroot_map[_jroot_roots]; \
int _jroot_cleans = (cleancount); \
void (*_jroot_cleanup[_jroot_cleans])(); \
OurContext* _jroot_context = (context); \
int _jroot_idx = 0
int _jroot_cleanidx = 0; \
int _jroot_rootidx = 0

#define PREPARE_JROOTS(context, name, maxcount) \
_PREPARE_JROOTS(false, context, name, maxcount)
#define PREPARE_JROOTS(context, rootcount, cleancount) \
_PREPARE_JROOTS(false, context, rootcount, cleancount)

#define PREPARE_RUBY_JROOTS(context, name, maxcount) \
_PREPARE_JROOTS(true, context, name, maxcount)
#define PREPARE_RUBY_JROOTS(context, rootcount, cleancount) \
_PREPARE_JROOTS(true, context, rootcount, cleancount)

#define _JROOT(ptr, name) \
do \
{ \
char _jroot_tmpname[_JROOT_NAMESIZE]; \
assert(_jroot_idx < _jroot_avail); \
_jroot_map[_jroot_idx] = (ptr); \
snprintf(_jroot_tmpname, _JROOT_NAMESIZE, "%s[%d]:%s: %s", __FILE__, __LINE__, _jroot_basename, (name)); \
JCHECK(JS_AddNamedRoot(_jroot_context->js, _jroot_map[_jroot_idx], _jroot_tmpname)); \
_jroot_idx++; \
assert(_jroot_rootidx < _jroot_roots); \
_jroot_map[_jroot_rootidx] = (ptr); \
snprintf(_jroot_tmpname, _JROOT_NAMESIZE, "%s[%d]:%s: %s", __FILE__, __LINE__, __func__, (name)); \
JCHECK(JS_AddNamedRoot(_jroot_context->js, _jroot_map[_jroot_rootidx], _jroot_tmpname)); \
_jroot_rootidx++; \
} while(0)

#define JROOT(var) _JROOT(&(var), #var)
#define JROOT_PTR(ptr) _JROOT(ptr, #ptr)

#define JCLEANUP(code) \
do \
{ \
assert(_jroot_cleanidx < _jroot_cleans); \
void _jroot_cleanup_func () { code; }; \
_jroot_cleanup[_jroot_cleanidx] = _jroot_cleanup_func; \
_jroot_cleanidx++; \
} while(0)

#define JUNROOT(var) \
do \
{ \
void* _jroot_match = &(var); \
int _jroot_i; \
for (_jroot_i = _jroot_idx - 1; _jroot_i >= 0; _jroot_i--) \
for (_jroot_i = _jroot_rootidx - 1; _jroot_i >= 0; _jroot_i--) \
if (_jroot_map[_jroot_i] == _jroot_match) \
{ \
JS_RemoveRoot(_jroot_context->js, _jroot_map[_jroot_i]); \
if (_jroot_i == _jroot_idx - 1) _jroot_idx--; \
if (_jroot_i == _jroot_rootidx - 1) _jroot_rootidx--; \
_jroot_map[_jroot_i] = NULL; \
} \
} while (0)
Expand All @@ -58,9 +69,12 @@
do \
{ \
int _jroot_i; \
for (_jroot_i = _jroot_idx - 1; _jroot_i >= 0; _jroot_i--) \
for (_jroot_i = _jroot_rootidx - 1; _jroot_i >= 0; _jroot_i--) \
if (_jroot_map[_jroot_i]) \
JS_RemoveRoot(_jroot_context->js, _jroot_map[_jroot_i]); \
for (_jroot_i = _jroot_cleanidx - 1; _jroot_i >= 0; _jroot_i--) \
if (_jroot_cleanup[_jroot_i]) \
(_jroot_cleanup[_jroot_i])(); \
} while (0)

#define JCHECK(cond) \
Expand Down
20 changes: 10 additions & 10 deletions ext/spidermonkey/js_land_proxy.c
Expand Up @@ -222,7 +222,7 @@ static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
OurContext* context;
Data_Get_Struct(ruby_context, OurContext, context);

PREPARE_JROOTS(context, "get", 1);
PREPARE_JROOTS(context, 1, 0);
JROOT(id);

// get the Ruby object that backs this proxy
Expand Down Expand Up @@ -310,7 +310,7 @@ static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
static JSBool get_and_destroy_resolved_property(
JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
{
PREPARE_JROOTS(OUR_CONTEXT(js_context), "get_and_destroy_resolved_property", 1);
PREPARE_JROOTS(OUR_CONTEXT(js_context), 1, 0);
JROOT(id);
char* name = JS_GetStringBytes(JSVAL_TO_STRING(id));
JCHECK(JS_DeleteProperty(js_context, obj, name));
Expand All @@ -325,7 +325,7 @@ static JSBool set(JSContext* js_context, JSObject* obj, jsval id, jsval* value)
OurContext* context;
Data_Get_Struct(ruby_context, OurContext, context);

PREPARE_JROOTS(context, "set", 2);
PREPARE_JROOTS(context, 2, 0);
JROOT(id);
JROOT_PTR(value);

Expand Down Expand Up @@ -391,7 +391,7 @@ static JSBool construct(JSContext* js_context, JSObject* UNUSED(obj), uintN argc
OurContext* context;
Data_Get_Struct(ruby_context, OurContext, context);

PREPARE_JROOTS(context, "construct", 0);
PREPARE_JROOTS(context, 0, 0);

VALUE klass = convert_to_ruby(context, JS_ARGV_CALLEE(argv));
VALUE args = rb_ary_new();
Expand All @@ -412,7 +412,7 @@ static JSBool resolve(JSContext *js_context, JSObject *obj, jsval id, uintN UNUS
OurContext* context;
Data_Get_Struct(ruby_context, OurContext, context);

PREPARE_JROOTS(context, "resolve", 1);
PREPARE_JROOTS(context, 1, 0);
JROOT(id);

char* name = JS_GetStringBytes(JS_ValueToString(js_context, id));
Expand All @@ -435,7 +435,7 @@ static JSBool to_string(JSContext* js_context, JSObject* obj, uintN UNUSED(argc)
OurContext* context;
Data_Get_Struct(ruby_context, OurContext, context);

PREPARE_JROOTS(context, "to_string", 0);
PREPARE_JROOTS(context, 0, 0);

VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL);

Expand All @@ -450,7 +450,7 @@ static JSBool to_array(JSContext* js_context, JSObject* obj, uintN UNUSED(argc),
OurContext* context;
Data_Get_Struct(ruby_context, OurContext, context);

PREPARE_JROOTS(context, "to_array", 0);
PREPARE_JROOTS(context, 0, 0);

VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL);

Expand All @@ -465,7 +465,7 @@ static JSBool method_missing(JSContext* js_context, JSObject* obj, uintN argc, j
OurContext* context;
Data_Get_Struct(ruby_context, OurContext, context);

PREPARE_JROOTS(context, "method_missing", 0);
PREPARE_JROOTS(context, 0, 0);

VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL);

Expand All @@ -491,7 +491,7 @@ static JSBool call(JSContext* js_context, JSObject* UNUSED(obj), uintN argc, jsv
OurContext* context;
Data_Get_Struct(ruby_context, OurContext, context);

PREPARE_JROOTS(context, "call", 0);
PREPARE_JROOTS(context, 0, 0);

VALUE self = (VALUE)JS_GetInstancePrivate(context->js, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)), &JSLandCallableProxyClass, NULL);

Expand Down Expand Up @@ -557,7 +557,7 @@ JSBool make_js_land_proxy(OurContext* context, VALUE value, jsval* retval)
}
else
{
PREPARE_JROOTS(context, "make_js_land_proxy", 1);
PREPARE_JROOTS(context, 1, 0);

JSObject *jsobj;

Expand Down
28 changes: 13 additions & 15 deletions ext/spidermonkey/ruby_land_proxy.c
Expand Up @@ -6,7 +6,7 @@ static VALUE proxy_class = Qnil;

static VALUE call_js_function_value(OurContext* context, jsval target, jsval function, int argc, VALUE* argv)
{
PREPARE_RUBY_JROOTS(context, "call_js_function_value", argc + 2);
PREPARE_RUBY_JROOTS(context, argc + 2, 0);

JROOT(target);
JROOT(function);
Expand Down Expand Up @@ -35,7 +35,7 @@ get(VALUE self, VALUE name)
RubyLandProxy* proxy;
Data_Get_Struct(self, RubyLandProxy, proxy);

PREPARE_RUBY_JROOTS(proxy->context, "get", 1);
PREPARE_RUBY_JROOTS(proxy->context, 1, 0);

JROOT(proxy->value);

Expand All @@ -62,7 +62,7 @@ set(VALUE self, VALUE name, VALUE value)
RubyLandProxy* proxy;
Data_Get_Struct(self, RubyLandProxy, proxy);

PREPARE_RUBY_JROOTS(proxy->context, "set", 2);
PREPARE_RUBY_JROOTS(proxy->context, 2, 0);
JROOT(proxy->value);

jsval js_value;
Expand Down Expand Up @@ -99,7 +99,7 @@ respond_to_p(VALUE self, VALUE sym)
RubyLandProxy* proxy;
Data_Get_Struct(self, RubyLandProxy, proxy);

PREPARE_RUBY_JROOTS(proxy->context, "respond_to_p", 2);
PREPARE_RUBY_JROOTS(proxy->context, 2, 0);

char* name = rb_id2name(SYM2ID(sym));

Expand Down Expand Up @@ -132,7 +132,7 @@ native_call(int argc, VALUE* argv, VALUE self)
RubyLandProxy* proxy;
Data_Get_Struct(self, RubyLandProxy, proxy);

PREPARE_RUBY_JROOTS(proxy->context, "native_call", 1);
PREPARE_RUBY_JROOTS(proxy->context, 1, 0);
JROOT(proxy->value);

jsval global;
Expand All @@ -147,7 +147,7 @@ each(VALUE self)
RubyLandProxy* proxy;
Data_Get_Struct(self, RubyLandProxy, proxy);

PREPARE_RUBY_JROOTS(proxy->context, "each", 4);
PREPARE_RUBY_JROOTS(proxy->context, 4, 1);
JROOT(proxy->value);

JSObject* value = JSVAL_TO_OBJECT(proxy->value);
Expand Down Expand Up @@ -179,8 +179,8 @@ each(VALUE self)
JSIdArray *ids = JS_Enumerate(proxy->context->js, value);
JCHECK(ids);

// FIXME: We leak ids if something goes wrong inside this loop...
JCLEANUP(JS_DestroyIdArray(proxy->context->js, ids));

int i;
for (i = 0; i < ids->length; ++i)
{
Expand Down Expand Up @@ -217,8 +217,6 @@ each(VALUE self)
JUNROOT(js_value);
JUNROOT(js_key);
}

JS_DestroyIdArray(proxy->context->js, ids);
}

JRETURN_RUBY(self);
Expand All @@ -230,7 +228,7 @@ length(VALUE self)
RubyLandProxy* proxy;
Data_Get_Struct(self, RubyLandProxy, proxy);

PREPARE_RUBY_JROOTS(proxy->context, "length", 2);
PREPARE_RUBY_JROOTS(proxy->context, 2, 0);

JROOT(proxy->value);

Expand Down Expand Up @@ -272,7 +270,7 @@ function_property_p(VALUE self, VALUE name)
RubyLandProxy* proxy;
Data_Get_Struct(self, RubyLandProxy, proxy);

PREPARE_RUBY_JROOTS(proxy->context, "function_property_p", 2);
PREPARE_RUBY_JROOTS(proxy->context, 2, 0);

JROOT(proxy->value);

Expand All @@ -297,7 +295,7 @@ call_function_property(int argc, VALUE* argv, VALUE self)
if (argc < 1)
rb_raise(rb_eArgError, "Function name required");

PREPARE_RUBY_JROOTS(proxy->context, "call_function_property", 2);
PREPARE_RUBY_JROOTS(proxy->context, 2, 0);
JROOT(proxy->value);

jsval function;
Expand Down Expand Up @@ -372,7 +370,7 @@ VALUE make_ruby_land_proxy(OurContext* context, jsval value)
RubyLandProxy* our_proxy;
VALUE proxy = Data_Make_Struct(proxy_class, RubyLandProxy, 0, finalize, our_proxy);

PREPARE_RUBY_JROOTS(context, "make_ruby_land_proxy", 1);
PREPARE_RUBY_JROOTS(context, 1, 0);
JROOT(value);

our_proxy->value = value;
Expand All @@ -395,7 +393,7 @@ static VALUE to_s(VALUE self)
RubyLandProxy* proxy;
Data_Get_Struct(self, RubyLandProxy, proxy);

PREPARE_RUBY_JROOTS(proxy->context, "to_s", 1);
PREPARE_RUBY_JROOTS(proxy->context, 1, 0);
JROOT(proxy->value);
JSString* str = JS_ValueToString(proxy->context->js, proxy->value);

Expand Down

0 comments on commit ce00ab6

Please sign in to comment.