#include #include #include #include #include "h8.h" #include "ruby_gate.h" void h8::JsError::raise() { if (has_js_exception) { VALUE ruby_exception; { // raising exception does longjump so we should keep all memory // allocation done before: H8::Scope scope(h8); Local jsx = exception().As(); Local source = jsx->Get(h8->js("source")); RubyGate *rg = RubyGate::unwrap(source.As()); if (rg) { // Passing thru the Ruby exception ruby_exception = rg->rubyObject(); } else { Local m = message(); Local s = m->Get(); String::Utf8Value res(s->ToString()); ruby_exception = ruby_exception = rb_exc_new2(js_exception, *res ? *res : "unknown javascript exception"); rb_iv_set(ruby_exception, "@message", h8->to_ruby(s)); rb_iv_set(ruby_exception, "@javascript_error", h8->to_ruby(jsx)); } } rb_exc_raise(ruby_exception); // } } else { rb_raise(h8_exception, "%s", reason); } } void h8::JsTimeoutError::raise() { rb_raise(js_timeout_exception, "timeout expired"); } Local h8::H8::gateObject(VALUE ruby_value) { if ( Qtrue == rb_funcall(ruby_value, id_is_a, 1, value_class)) { JsGate *gate; Data_Get_Struct(ruby_value, JsGate, gate); if (gate->h8 != this) { throw JsError(this, "H8::Value is bound to other H8::Context"); } else return gate->value(); } // Generic Ruby object RubyGate *gate = new RubyGate(this, ruby_value); return gate->handle(isolate); } void h8::H8::ruby_mark_gc() const { for (chain::link *x : resources) ((AllocatedResource*) x)->rb_mark_gc(); } v8::Handle h8::H8::eval(const char* script_utf,unsigned max_ms) { v8::EscapableHandleScope escape(isolate); Local result; Handle script_source = String::NewFromUtf8(isolate, script_utf); v8::Handle script; JsCatcher try_catch(this); v8::ScriptOrigin origin(String::NewFromUtf8(isolate, "eval")); script = v8::Script::Compile(script_source, &origin); if (script.IsEmpty()) { try_catch.throwIfCaught(); result = Undefined(isolate); } else { result = Undefined(isolate); if( max_ms > 0 ) { std::mutex m; std::condition_variable cv; std::thread thr( [&] { std::unique_lock lock(m); if( std::cv_status::timeout == cv.wait_for(lock, std::chrono::milliseconds(max_ms) ) ) { isolate->TerminateExecution(); } }); script->Run(); cv.notify_all(); thr.join(); } else { result = script->Run(); } try_catch.throwIfCaught(); } return escape.Escape(result); } h8::H8::~H8() { while (!resources.is_empty()) { // this should also remove it from the list: resources.peek_first()->free(); } persistent_context.Reset(); isolate->Dispose(); }