diff --git a/ext/mini_racer_extension/extconf.rb b/ext/mini_racer_extension/extconf.rb index 55d7334c..1033ad2d 100644 --- a/ext/mini_racer_extension/extconf.rb +++ b/ext/mini_racer_extension/extconf.rb @@ -11,6 +11,7 @@ $CPPFLAGS += " -fPIC" unless $CPPFLAGS.split.include? "-rdynamic" or IS_DARWIN $CPPFLAGS += " -std=c++0x" $CPPFLAGS += " -fpermissive" +$CPPFLAGS += " -DV8_COMPRESS_POINTERS" $CPPFLAGS += " -Wno-reserved-user-defined-literal" if IS_DARWIN diff --git a/ext/mini_racer_extension/mini_racer_extension.cc b/ext/mini_racer_extension/mini_racer_extension.cc index 2fff58d3..e8aafd85 100644 --- a/ext/mini_racer_extension/mini_racer_extension.cc +++ b/ext/mini_racer_extension/mini_racer_extension.cc @@ -25,6 +25,7 @@ class IsolateInfo { ArrayBuffer::Allocator* allocator; StartupData* startup_data; bool interrupted; + bool added_gc_cb; pid_t pid; VALUE mutex; @@ -42,15 +43,12 @@ class IsolateInfo { IsolateInfo() : isolate(nullptr), allocator(nullptr), startup_data(nullptr), - interrupted(false), pid(getpid()), refs_count(0) { + interrupted(false), added_gc_cb(false), pid(getpid()), refs_count(0) { VALUE cMutex = rb_const_get(rb_cThread, rb_intern("Mutex")); mutex = rb_class_new_instance(0, nullptr, cMutex); } - ~IsolateInfo() { - void free_isolate(IsolateInfo*); - free_isolate(this); - } + ~IsolateInfo(); void init(SnapshotInfo* snapshot_info = nullptr); @@ -237,11 +235,13 @@ static void prepare_result(MaybeLocal v8res, Local local_value = v8res.ToLocalChecked(); if ((local_value->IsObject() || local_value->IsArray()) && !local_value->IsDate() && !local_value->IsFunction()) { - Local JSON = context->Global()->Get(String::NewFromUtf8(isolate, "JSON")) - ->ToObject(context).ToLocalChecked(); + Local JSON = context->Global()->Get( + context, String::NewFromUtf8Literal(isolate, "JSON")) + .ToLocalChecked().As(); - Local stringify = JSON->Get(v8::String::NewFromUtf8(isolate, "stringify")) - .As(); + Local stringify = JSON->Get( + context, v8::String::NewFromUtf8Literal(isolate, "stringify")) + .ToLocalChecked().As(); Local object = local_value->ToObject(context).ToLocalChecked(); const unsigned argc = 1; @@ -295,7 +295,7 @@ static void prepare_result(MaybeLocal v8res, } else if(trycatch.HasTerminated()) { evalRes.terminated = true; evalRes.message = new Persistent(); - Local tmp = String::NewFromUtf8(isolate, "JavaScript was terminated (either by timeout or explicitly)"); + Local tmp = String::NewFromUtf8Literal(isolate, "JavaScript was terminated (either by timeout or explicitly)"); evalRes.message->Reset(isolate, tmp); } if (!trycatch.StackTrace(context).IsEmpty()) { @@ -312,7 +312,8 @@ nogvl_context_eval(void* arg) { EvalParams* eval_params = (EvalParams*)arg; EvalResult* result = eval_params->result; - Isolate* isolate = eval_params->context_info->isolate_info->isolate; + IsolateInfo* isolate_info = eval_params->context_info->isolate_info; + Isolate* isolate = isolate_info->isolate; Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); @@ -356,7 +357,10 @@ nogvl_context_eval(void* arg) { // parsing successful if (eval_params->max_memory > 0) { isolate->SetData(MEM_SOFTLIMIT_VALUE, &eval_params->max_memory); + if (!isolate_info->added_gc_cb) { isolate->AddGCEpilogueCallback(gc_callback); + isolate_info->added_gc_cb = true; + } } maybe_value = parsed_script.ToLocalChecked()->Run(context); @@ -369,6 +373,12 @@ nogvl_context_eval(void* arg) { return NULL; } +static VALUE new_empty_failed_conv_obj() { + // TODO isolate code that translates execption to ruby + // exception so we can properly return it + return rb_funcall(rb_cFailedV8Conversion, rb_intern("new"), 1, rb_str_new2("")); +} + // assumes isolate locking is in place static VALUE convert_v8_to_ruby(Isolate* isolate, Local context, Local value) { @@ -400,8 +410,11 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local context, VALUE rb_array = rb_ary_new(); Local arr = Local::Cast(value); for(uint32_t i=0; i < arr->Length(); i++) { - Local element = arr->Get(i); - VALUE rb_elem = convert_v8_to_ruby(isolate, context, element); + MaybeLocal element = arr->Get(context, i); + if (element.IsEmpty()) { + continue; + } + VALUE rb_elem = convert_v8_to_ruby(isolate, context, element.ToLocalChecked()); if (rb_funcall(rb_elem, rb_intern("class"), 0) == rb_cFailedV8Conversion) { return rb_elem; } @@ -431,18 +444,20 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local context, if (!maybe_props.IsEmpty()) { Local props = maybe_props.ToLocalChecked(); for(uint32_t i=0; i < props->Length(); i++) { - Local key = props->Get(i); - VALUE rb_key = convert_v8_to_ruby(isolate, context, key); - Local prop_value = object->Get(key); - // this may have failed due to Get raising + MaybeLocal key = props->Get(context, i); + if (key.IsEmpty()) { + return rb_funcall(rb_cFailedV8Conversion, rb_intern("new"), 1, rb_str_new2("")); + } + VALUE rb_key = convert_v8_to_ruby(isolate, context, key.ToLocalChecked()); - if (trycatch.HasCaught()) { - // TODO isolate code that translates execption to ruby - // exception so we can properly return it - return rb_funcall(rb_cFailedV8Conversion, rb_intern("new"), 1, rb_str_new2("")); + MaybeLocal prop_value = object->Get(context, key.ToLocalChecked()); + // this may have failed due to Get raising + if (prop_value.IsEmpty() || trycatch.HasCaught()) { + return new_empty_failed_conv_obj(); } - VALUE rb_value = convert_v8_to_ruby(isolate, context, prop_value); + VALUE rb_value = convert_v8_to_ruby( + isolate, context, prop_value.ToLocalChecked()); rb_hash_aset(rb_hash, rb_key, rb_value); } } @@ -524,7 +539,7 @@ static Local convert_ruby_to_v8(Isolate* isolate, Local context, length = RARRAY_LEN(value); array = Array::New(isolate, (int)length); for(i=0; iSet(i, convert_ruby_to_v8(isolate, context, rb_ary_entry(value, i))); + array->Set(context, i, convert_ruby_to_v8(isolate, context, rb_ary_entry(value, i))); } return scope.Escape(array); case T_HASH: @@ -533,7 +548,7 @@ static Local convert_ruby_to_v8(Isolate* isolate, Local context, length = RARRAY_LEN(hash_as_array); for(i=0; iSet(convert_ruby_to_v8(isolate, context, rb_ary_entry(pair, 0)), + object->Set(context, convert_ruby_to_v8(isolate, context, rb_ary_entry(pair, 0)), convert_ruby_to_v8(isolate, context, rb_ary_entry(pair, 1))); } return scope.Escape(object); @@ -563,9 +578,9 @@ static Local convert_ruby_to_v8(Isolate* isolate, Local context, case T_UNDEF: case T_NODE: default: - return scope.Escape(String::NewFromUtf8(isolate, "Undefined Conversion")); + return scope.Escape(String::NewFromUtf8Literal(isolate, "Undefined Conversion")); + } } -} static void unblock_eval(void *ptr) { EvalParams* eval = (EvalParams*)ptr; @@ -576,53 +591,43 @@ static void unblock_eval(void *ptr) { * The implementations of the run_extra_code(), create_snapshot_data_blob() and * warm_up_snapshot_data_blob() functions have been derived from V8's test suite. */ -bool run_extra_code(Isolate *isolate, Local context, +static bool run_extra_code(Isolate *isolate, Local context, const char *utf8_source, const char *name) { Context::Scope context_scope(context); TryCatch try_catch(isolate); Local source_string; - if (!String::NewFromUtf8(isolate, utf8_source, - NewStringType::kNormal) - .ToLocal(&source_string)) { + if (!String::NewFromUtf8(isolate, utf8_source).ToLocal(&source_string)) { return false; } - Local resource_name = - String::NewFromUtf8(isolate, name, NewStringType::kNormal) - .ToLocalChecked(); + Local resource_name = + String::NewFromUtf8(isolate, name).ToLocalChecked(); ScriptOrigin origin(resource_name); ScriptCompiler::Source source(source_string, origin); Local