1313#include "serde.c"
1414#include "mini_racer_v8.h"
1515
16+ // for debugging
17+ #define RB_PUTS (v ) \
18+ do { \
19+ fflush(stdout); \
20+ rb_funcall(rb_mKernel, rb_intern("puts"), 1, v); \
21+ } while (0)
22+
1623#if RUBY_API_VERSION_CODE < 3 * 10000 + 4 * 100 // 3.4.0
1724static inline void rb_thread_lock_native_thread (void )
1825{
@@ -154,6 +161,7 @@ static VALUE platform_init_error;
154161static VALUE context_disposed_error ;
155162static VALUE parse_error ;
156163static VALUE memory_error ;
164+ static VALUE script_error ;
157165static VALUE runtime_error ;
158166static VALUE internal_error ;
159167static VALUE snapshot_error ;
@@ -482,12 +490,36 @@ static void des_object_ref(void *arg, uint32_t id)
482490
483491static void des_error_begin (void * arg )
484492{
485- push (arg , rb_class_new_instance ( 0 , NULL , rb_eRuntimeError ));
493+ push (arg , rb_ary_new ( ));
486494}
487495
488496static void des_error_end (void * arg )
489497{
490- pop (arg );
498+ VALUE * a , h , message , stack , cause , newline ;
499+ DesCtx * c ;
500+
501+ c = arg ;
502+ if (* c -> err )
503+ return ;
504+ if (c -> tos == c -> stack ) {
505+ snprintf (c -> err , sizeof (c -> err ), "stack underflow" );
506+ return ;
507+ }
508+ a = & c -> tos -> a ;
509+ h = rb_ary_pop (* a );
510+ message = rb_hash_aref (h , rb_str_new_cstr ("message" ));
511+ stack = rb_hash_aref (h , rb_str_new_cstr ("stack" ));
512+ cause = rb_hash_aref (h , rb_str_new_cstr ("cause" ));
513+ if (NIL_P (message ))
514+ message = rb_str_new_cstr ("JS exception" );
515+ if (!NIL_P (stack )) {
516+ newline = rb_str_new_cstr ("\n" );
517+ message = rb_funcall (message , rb_intern ("concat" ), 2 , newline , stack );
518+ }
519+ * a = rb_class_new_instance (1 , & message , script_error );
520+ if (!NIL_P (cause ))
521+ rb_iv_set (* a , "@cause" , cause );
522+ pop (c );
491523}
492524
493525static int collect (VALUE k , VALUE v , VALUE a )
@@ -894,6 +926,7 @@ static VALUE rendezvous_callback_do(VALUE arg)
894926static void * rendezvous_callback (void * arg )
895927{
896928 struct rendezvous_nogvl * a ;
929+ const char * err ;
897930 Context * c ;
898931 int exc ;
899932 VALUE r ;
@@ -917,7 +950,12 @@ static void *rendezvous_callback(void *arg)
917950 buf_move (& s .b , a -> req );
918951 return NULL ;
919952fail :
920- ser_init1 (& s , 'e' ); // exception pending
953+ ser_init0 (& s ); // ruby exception pending
954+ w_byte (& s , 'e' ); // send ruby error message to v8 thread
955+ r = rb_funcall (c -> exception , rb_intern ("to_s" ), 0 );
956+ err = StringValueCStr (r );
957+ if (err )
958+ w (& s , err , strlen (err ));
921959 goto out ;
922960}
923961
@@ -975,18 +1013,20 @@ static VALUE rendezvous1(Context *c, Buf *req, DesCtx *d)
9751013 int exc ;
9761014
9771015 rendezvous_no_des (c , req , & res ); // takes ownership of |req|
1016+ r = c -> exception ;
1017+ c -> exception = Qnil ;
1018+ // if js land didn't handle exception from ruby callback, re-raise it now
1019+ if (res .len == 1 && * res .buf == 'e' ) {
1020+ assert (!NIL_P (r ));
1021+ rb_exc_raise (r );
1022+ }
9781023 r = rb_protect (deserialize , (VALUE )& (struct rendezvous_des ){d , & res }, & exc );
9791024 buf_reset (& res );
9801025 if (exc ) {
9811026 r = rb_errinfo ();
9821027 rb_set_errinfo (Qnil );
9831028 rb_exc_raise (r );
9841029 }
985- if (!NIL_P (c -> exception )) {
986- r = c -> exception ;
987- c -> exception = Qnil ;
988- rb_exc_raise (r );
989- }
9901030 return r ;
9911031}
9921032
@@ -1634,6 +1674,11 @@ static VALUE snapshot_size0(VALUE self)
16341674 return LONG2FIX (RSTRING_LENINT (ss -> blob ));
16351675}
16361676
1677+ static VALUE script_error_cause (VALUE self )
1678+ {
1679+ return rb_iv_get (self , "@cause" );
1680+ }
1681+
16371682__attribute__((visibility ("default" )))
16381683void Init_mini_racer_extension (void )
16391684{
@@ -1648,10 +1693,13 @@ void Init_mini_racer_extension(void)
16481693 c = rb_define_class_under (m , "EvalError" , c );
16491694 parse_error = rb_define_class_under (m , "ParseError" , c );
16501695 memory_error = rb_define_class_under (m , "V8OutOfMemoryError" , c );
1696+ script_error = rb_define_class_under (m , "ScriptError" , c );
16511697 runtime_error = rb_define_class_under (m , "RuntimeError" , c );
16521698 internal_error = rb_define_class_under (m , "InternalError" , c );
16531699 terminated_error = rb_define_class_under (m , "ScriptTerminatedError" , c );
16541700
1701+ rb_define_method (script_error , "cause" , script_error_cause , 0 );
1702+
16551703 c = context_class = rb_define_class_under (m , "Context" , rb_cObject );
16561704 rb_define_method (c , "initialize" , context_initialize , -1 );
16571705 rb_define_method (c , "attach" , context_attach , 2 );
0 commit comments