Skip to content
Browse files

objc exceptions should now be catchable in ruby

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/trunk@2747 23306eb0-4c56-4727-a40e-e92c0eb68959
  • Loading branch information...
1 parent 76a82ce commit bd7eba32c6cd9901ce89b1d8f398d24b57d5da3a Laurent Sansonetti committed Oct 7, 2009
Showing with 60 additions and 8 deletions.
  1. +29 −1 dispatcher.cpp
  2. +2 −1 objc.h
  3. +10 −1 objc.m
  4. +15 −1 rakelib/builder.rake
  5. +2 −2 rakelib/builder.rb
  6. +2 −2 vm.cpp
View
30 dispatcher.cpp
@@ -391,6 +391,33 @@ __rb_vm_ruby_dispatch(VALUE self, SEL sel, rb_vm_method_node_t *node,
return __rb_vm_rcall(self, sel, node->ruby_imp, arity, argc, argv);
}
+static
+#if __LP64__
+// This method can't be inlined in 32-bit because @try compiles as a call
+// to setjmp().
+force_inline
+#endif
+VALUE
+__rb_vm_objc_dispatch(rb_vm_objc_stub_t *stub, IMP imp, id rcv, SEL sel,
+ int argc, const VALUE *argv)
+{
+ @try {
+ return (*stub)(imp, rcv, sel, argc, argv);
+ }
+ @catch (id exc) {
+ VALUE rbexc = rb_oc2rb_exception(exc);
+#if __LP64__
+ if (rb_vm_current_exception() == Qnil) {
+ rb_vm_set_current_exception(rbexc);
+ }
+ throw;
+#else
+ rb_exc_raise(rbexc);
+#endif
+ }
+ abort(); // never reached
+}
+
static void
fill_rcache(struct mcache *cache, Class klass, SEL sel,
rb_vm_method_node_t *node)
@@ -783,7 +810,8 @@ __rb_vm_dispatch(RoxorVM *vm, struct mcache *cache, VALUE self, Class klass,
}
}
- return (*ocache.stub)(ocache.imp, ocrcv, sel, argc, argv);
+ return __rb_vm_objc_dispatch(ocache.stub, ocache.imp, ocrcv, sel,
+ argc, argv);
}
else if (cache->flag == MCACHE_FCALL) {
#if ROXOR_VM_DEBUG
View
3 objc.h
@@ -77,7 +77,8 @@ rb_objc_is_placeholder(id obj)
bool rb_objc_symbolize_address(void *addr, void **start, char *name,
size_t name_len);
-id rb_objc_create_exception(VALUE exc);
+id rb_rb2oc_exception(VALUE exc);
+VALUE rb_oc2rb_exception(id exc);
static inline int
SubtypeUntil(const char *type, char end)
View
11 objc.m
@@ -622,7 +622,7 @@ - (VMURange)addressRange;
}
id
-rb_objc_create_exception(VALUE exc)
+rb_rb2oc_exception(VALUE exc)
{
NSString *name = [NSString stringWithUTF8String:rb_obj_classname(exc)];
NSString *reason = [(id)exc performSelector:@selector(message)];
@@ -637,6 +637,15 @@ - (VMURange)addressRange;
return [NSException exceptionWithName:name reason:reason userInfo:dict];
}
+VALUE
+rb_oc2rb_exception(id exc)
+{
+ char buf[1000];
+ snprintf(buf, sizeof buf, "%s: %s", [[exc name] UTF8String],
+ [[exc reason] UTF8String]);
+ return rb_exc_new2(rb_eRuntimeError, buf);
+}
+
void *placeholder_String = NULL;
void *placeholder_Dictionary = NULL;
void *placeholder_Array = NULL;
View
16 rakelib/builder.rake
@@ -35,8 +35,15 @@ module Rake
end
end
+desc "Build the markgc tool"
+task :mark_gc do
+ if !File.exist?('markgc')
+ sh "/usr/bin/gcc -std=c99 markgc.c -o markgc -Wno-format"
+ end
+end
+
desc "Build known objects"
-task :objects => [:config_h, :dtrace_h, :revision_h] do
+task :objects => [:config_h, :dtrace_h, :revision_h, :mark_gc] do
sh "/usr/bin/ruby tool/compile_prelude.rb prelude.rb miniprelude.c.new"
if !File.exist?('miniprelude.c') or File.read('miniprelude.c') != File.read('miniprelude.c.new')
mv('miniprelude.c.new', 'miniprelude.c')
@@ -62,7 +69,14 @@ task :objects => [:config_h, :dtrace_h, :revision_h] do
if !File.exist?('node_name.inc') or File.mtime('include/ruby/node.h') > File.mtime('node_name.inc')
sh("/usr/bin/ruby -n tool/node_name.rb include/ruby/node.h > node_name.inc")
end
+ t = File.exist?('dispatcher.o') ? File.mtime('dispatcher.o') : nil
$builder.build
+ if t == nil or File.mtime('dispatcher.o') > t
+ # dispatcher.o must be marked as GC compliant to avoid a linker problem.
+ # We do not build it using -fobjc-gc because gcc generates unnecessary (and slow) write
+ # barriers.
+ sh "./markgc ./dispatcher.o"
+ end
end
desc "Create miniruby"
View
4 rakelib/builder.rb
@@ -113,8 +113,8 @@ def do_option(name, default)
}
OBJS_CFLAGS = {
- # Make sure everything gets inlined properly.
- 'dispatcher' => '-Winline --param inline-unit-growth=10000 --param large-function-growth=10000'
+ # Make sure everything gets inlined properly + compile as Objective-C++.
+ 'dispatcher' => '-Winline --param inline-unit-growth=10000 --param large-function-growth=10000 -x objective-c++'
}
class Builder
View
4 vm.cpp
@@ -2784,7 +2784,7 @@ __vm_raise(void)
{
#if __LP64__
// In 64-bit, an Objective-C exception is a C++ exception.
- id exc = rb_objc_create_exception(GET_VM()->current_exception());
+ id exc = rb_rb2oc_exception(GET_VM()->current_exception());
objc_exception_throw(exc);
#else
void *exc = __cxa_allocate_exception(0);
@@ -2799,7 +2799,7 @@ rb2oc_exc_handler(void)
{
VALUE exc = GET_VM()->current_exception();
if (exc != Qnil) {
- id ocexc = rb_objc_create_exception(exc);
+ id ocexc = rb_rb2oc_exception(exc);
objc_exception_throw(ocexc);
}
else {

0 comments on commit bd7eba3

Please sign in to comment.
Something went wrong with that request. Please try again.