From a22348f73ee32b7860d7ba5b26bfed6c80a52e56 Mon Sep 17 00:00:00 2001 From: Petko Bordjukov Date: Thu, 25 Apr 2019 02:39:56 +0300 Subject: [PATCH] Introduce compatibility with V8 7.3 (#138) * Mechanical removal of use of non-maybe String::ToObject() Due to the non-maybe version of String::ToObject() being deprecated and altogether removed from V8 [1] it is necessary to migrate to using the maybe version. This commit is a mechanical change that uses the context at hand when calling String::ToObject() to pass it to it. The resulting MaybeLocal is then unwrapped with MaybeLocal::ToLocalChecked() as I consider the verifications performed on the String instances to be sufficient to ensure no crashes. [1] https://chromium-review.googlesource.com/c/v8/v8/+/1172350/ https://chromium.googlesource.com/v8/v8/+/c8376b0069ebe16c67acf90c3cda3457ddccba4f * Mechanical removal of use of non-maybe Local::ToString() Due to the non-maybe version of Local::ToString() being deprecated and altogether removed from V8 [1] it is necessary to migrate to using the maybe version. This commit is a mechanical change that uses the context at hand when calling Local::ToString() to pass it to it. The resulting MaybeLocal is then unwrapped with MaybeLocal::ToLocalChecked() as I consider the context of the uses to be sufficiently safe. [1] https://chromium-review.googlesource.com/c/v8/v8/+/1172350/ https://chromium.googlesource.com/v8/v8/+/c8376b0069ebe16c67acf90c3cda3457ddccba4f * Mechanical removal of the use of non-maybe Value::Int32Value() and NumberValue() Due to the non-maybe version of Value::Int32Value() and Value::NumberValue() being deprecated and altogether removed from V8 [1] it is necessary to migrate to using the maybe versions. This commit is a mechanical change that uses the context at hand when calling Value::Int32Value() or Value::NumberValue() to pass it to the respective function. The resulting Maybe is then unwrapped with Maybe::ToChecked() as I consider the verifications performed on the Value instances to be sufficient to ensure no crashes. [1] https://chromium-review.googlesource.com/c/v8/v8/+/1172350/ https://chromium.googlesource.com/v8/v8/+/c8376b0069ebe16c67acf90c3cda3457ddccba4f * Mechanical removal of use of String::Utf8Length() without isolate Due to the version of String::Utf8Length() with no paramters being deprecated and altogether removed from V8 [1] it is necessary to migrate to using the version that accepts isolate as a parameter. This commit is a mechanical change that uses the isolate available in the context where String::Utf8Length() is called. This is a breaking change imposing use of V8 6.9.411 or up. [1] https://chromium-review.googlesource.com/c/v8/v8/+/1124724/ https://chromium.googlesource.com/v8/v8/+/3dd5c6fe38355b8323597341409b37f931de5a85 * Remove the uses of deprecated snapshot-related functions Due to V8::CreateSnapshotDataBlob() and V8::WarmUpSnapshotDataBlob() being deprecated and altogether removed from V8 [1] it is necessary to migrate to using local implementations of them. This commit introduces create_snapshot_data_blob(), warm_up_snapshot_data_blob() and the helper function run_extra_code(). Their implementations have been copied over from [2]. [1] https://github.com/v8/v8/commit/b3738e658345adabaa958b9f9a94ca01fc87d5e4 https://chromium-review.googlesource.com/c/v8/v8/+/1019442/ [2] https://github.com/v8/v8/blob/7.3.492.27/test/cctest/test-serialize.cc https://chromium.googlesource.com/v8/v8.git/+/30602560a8fdb0bbfb50d70be867f32b72758a2f/test/cctest/test-serialize.cc * Non-trivial removal of uses of non-maybe Date::New() Due to the non-maybe version of Date::New() being deprecated and altogether removed from V8 [1] it is necessary to migrate to using the maybe version. This commit introduces a context argument to the convert_ruby_to_v8() function so it can be passed to the maybe version of Date::New(). This imposed changes throughout the code base so that the context can be passed together with the isolate to convert_ruby_to_v8(). [1] https://chromium-review.googlesource.com/c/v8/v8/+/1357056 https://github.com/v8/v8/commit/e84b92d7658dee79c34304a67c4fb84c93cd071b * Non-trivial removal of use of non-maybe Local::ToString() This commit builds upon fe62f7935582bd889742ec77ee2289a8f6cb16e6. The use of Local::ToString() in convert_result_to_ruby() did not have an immediately available context to use. This commit unwraps the context from p_ctx and passes it to the function and then unwraps the MaybeLocal result with MaybeLocal::ToLocalChecked() assuming the verification beforehand is sufficient to ensure there won't be any crashes. * Update the changelog * Replace placeholder in LICENSE.txt --- CHANGELOG | 6 + LICENSE.txt | 2 +- .../mini_racer_extension.cc | 134 ++++++++++++++---- mini_racer.gemspec | 2 +- 4 files changed, 118 insertions(+), 26 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c664a49c..729bbb41 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,9 @@ +- Unreleased + + - FIX: Compatiblity fixes for V8 7 and above @ignisf + - FIX: Memory leak in gc_callback @messense + - IMPROVEMENT: Added example of sourcemap support @ianks + - 02-11-2018 - 0.2.4 diff --git a/LICENSE.txt b/LICENSE.txt index 109b204f..87a6bf90 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016 TODO: Write your name +Copyright (c) 2016-2019, the mini_racer project authors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/ext/mini_racer_extension/mini_racer_extension.cc b/ext/mini_racer_extension/mini_racer_extension.cc index e2c11212..dad8f20b 100644 --- a/ext/mini_racer_extension/mini_racer_extension.cc +++ b/ext/mini_racer_extension/mini_racer_extension.cc @@ -230,13 +230,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(); + Local JSON = context->Global()->Get(String::NewFromUtf8(isolate, "JSON")) + ->ToObject(context).ToLocalChecked(); Local stringify = JSON->Get(v8::String::NewFromUtf8(isolate, "stringify")) .As(); - Local object = local_value->ToObject(); + Local object = local_value->ToObject(context).ToLocalChecked(); const unsigned argc = 1; Local argv[argc] = { object }; MaybeLocal json = stringify->Call(JSON, argc, argv); @@ -274,7 +274,7 @@ static void prepare_result(MaybeLocal v8res, } len = snprintf(buf, sizeof(buf), "%s at %s:%i:%i", *String::Utf8Value(isolate, message->Get()), - *String::Utf8Value(isolate, message->GetScriptResourceName()->ToString()), + *String::Utf8Value(isolate, message->GetScriptResourceName()->ToString(context).ToLocalChecked()), line, column); @@ -293,7 +293,8 @@ static void prepare_result(MaybeLocal v8res, } if (!trycatch.StackTrace(context).IsEmpty()) { evalRes.backtrace = new Persistent(); - evalRes.backtrace->Reset(isolate, trycatch.StackTrace(context).ToLocalChecked()->ToString()); + evalRes.backtrace->Reset(isolate, + trycatch.StackTrace(context).ToLocalChecked()->ToString(context).ToLocalChecked()); } } } @@ -373,11 +374,11 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local context, } if (value->IsInt32()) { - return INT2FIX(value->Int32Value()); + return INT2FIX(value->Int32Value(context).ToChecked()); } if (value->IsNumber()) { - return rb_float_new(value->NumberValue()); + return rb_float_new(value->NumberValue(context).ToChecked()); } if (value->IsTrue()) { @@ -418,7 +419,7 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local context, VALUE rb_hash = rb_hash_new(); TryCatch trycatch(isolate); - Local object = value->ToObject(); + Local object = value->ToObject(context).ToLocalChecked(); auto maybe_props = object->GetOwnPropertyNames(context); if (!maybe_props.IsEmpty()) { Local props = maybe_props.ToLocalChecked(); @@ -441,8 +442,8 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local context, return rb_hash; } - Local rstr = value->ToString(); - return rb_enc_str_new(*String::Utf8Value(isolate, rstr), rstr->Utf8Length(), rb_enc_find("utf-8")); + Local rstr = value->ToString(context).ToLocalChecked(); + return rb_enc_str_new(*String::Utf8Value(isolate, rstr), rstr->Utf8Length(isolate), rb_enc_find("utf-8")); } static VALUE convert_v8_to_ruby(Isolate* isolate, @@ -463,7 +464,7 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local::New(isolate, value)); } -static Local convert_ruby_to_v8(Isolate* isolate, VALUE value) { +static Local convert_ruby_to_v8(Isolate* isolate, Local context, VALUE value) { EscapableHandleScope scope(isolate); Local array; @@ -497,7 +498,7 @@ static Local convert_ruby_to_v8(Isolate* isolate, VALUE value) { length = RARRAY_LEN(value); array = Array::New(isolate, (int)length); for(i=0; iSet(i, convert_ruby_to_v8(isolate, rb_ary_entry(value, i))); + array->Set(i, convert_ruby_to_v8(isolate, context, rb_ary_entry(value, i))); } return scope.Escape(array); case T_HASH: @@ -506,8 +507,8 @@ static Local convert_ruby_to_v8(Isolate* isolate, VALUE value) { length = RARRAY_LEN(hash_as_array); for(i=0; iSet(convert_ruby_to_v8(isolate, rb_ary_entry(pair, 0)), - convert_ruby_to_v8(isolate, rb_ary_entry(pair, 1))); + object->Set(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); case T_SYMBOL: @@ -522,7 +523,7 @@ static Local convert_ruby_to_v8(Isolate* isolate, VALUE value) { value = rb_funcall(value, rb_intern("to_time"), 0); } value = rb_funcall(value, rb_intern("to_f"), 0); - return scope.Escape(Date::New(isolate, NUM2DBL(value) * 1000)); + return scope.Escape(Date::New(context, NUM2DBL(value) * 1000).ToLocalChecked()); } case T_OBJECT: case T_CLASS: @@ -538,7 +539,6 @@ static Local convert_ruby_to_v8(Isolate* isolate, VALUE value) { default: return scope.Escape(String::NewFromUtf8(isolate, "Undefined Conversion")); } - } static void unblock_eval(void *ptr) { @@ -546,6 +546,91 @@ static void unblock_eval(void *ptr) { eval->context_info->isolate_info->interrupted = true; } +/* + * 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, + 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)) { + return false; + } + Local resource_name = + String::NewFromUtf8(isolate, name, NewStringType::kNormal) + .ToLocalChecked(); + ScriptOrigin origin(resource_name); + ScriptCompiler::Source source(source_string, origin); + Local