Introduce compatibility with V8 7.3 (#138)

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/ c8376b0069ebe16c67acf90c3cda3457ddccba4f - v8/v8 - Git at Google

  • 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/ c8376b0069ebe16c67acf90c3cda3457ddccba4f - v8/v8 - Git at Google

  • 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/ c8376b0069ebe16c67acf90c3cda3457ddccba4f - v8/v8 - Git at Google

  • 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/ 3dd5c6fe38355b8323597341409b37f931de5a85 - v8/v8 - Git at Google

  • 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] [api] Deprecate {Create,WarmUp}SnapshotDataBlob · v8/v8@b3738e6 · GitHub https://chromium-review.googlesource.com/c/v8/v8/+/1019442/

[2] v8/test-serialize.cc at 7.3.492.27 · v8/v8 · GitHub test/cctest/test-serialize.cc - v8/v8.git - Git at Google

  • 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 [api] Remove deprecations from before version 7.2 · v8/v8@e84b92d · GitHub

  • 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

diff --git a/CHANGELOG b/CHANGELOG
index c664a49..729bbb4 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 109b204..87a6bf9 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 e2c1121..dad8f20 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<Value> v8res,
         Local<Value> local_value = v8res.ToLocalChecked();
         if ((local_value->IsObject() || local_value->IsArray()) &&
                 !local_value->IsDate() && !local_value->IsFunction()) {
-            Local<Object> JSON = context->Global()->Get(
-                        String::NewFromUtf8(isolate, "JSON"))->ToObject();
+            Local<Object> JSON = context->Global()->Get(String::NewFromUtf8(isolate, "JSON"))
+              ->ToObject(context).ToLocalChecked();
 
             Local<Function> stringify = JSON->Get(v8::String::NewFromUtf8(isolate, "stringify"))
                     .As<Function>();
 
-            Local<Object> object = local_value->ToObject();
+            Local<Object> object = local_value->ToObject(context).ToLocalChecked();
             const unsigned argc = 1;
             Local<Value> argv[argc] = { object };
             MaybeLocal<Value> json = stringify->Call(JSON, argc, argv);
@@ -274,7 +274,7 @@ static void prepare_result(MaybeLocal<Value> 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<Value> v8res,
             }
             if (!trycatch.StackTrace(context).IsEmpty()) {
                 evalRes.backtrace = new Persistent<Value>();
-                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> 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> context,
         VALUE rb_hash = rb_hash_new();
         TryCatch trycatch(isolate);
 
-        Local<Object> object = value->ToObject();
+        Local<Object> object = value->ToObject(context).ToLocalChecked();
         auto maybe_props = object->GetOwnPropertyNames(context);
         if (!maybe_props.IsEmpty()) {
             Local<Array> props = maybe_props.ToLocalChecked();
@@ -441,8 +442,8 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Local<Context> context,
         return rb_hash;
     }
 
-    Local<String> rstr = value->ToString();
-    return rb_enc_str_new(*String::Utf8Value(isolate, rstr), rstr->Utf8Length(), rb_enc_find("utf-8"));
+    Local<String> 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<Value>::New(isolate, value));
 }
 
-static Local<Value> convert_ruby_to_v8(Isolate* isolate, VALUE value) {
+static Local<Value> convert_ruby_to_v8(Isolate* isolate, Local<Context> context, VALUE value) {
     EscapableHandleScope scope(isolate);
 
     Local<Array> array;
@@ -497,7 +498,7 @@ static Local<Value> convert_ruby_to_v8(Isolate* isolate, VALUE value) {
 	length = RARRAY_LEN(value);
 	array = Array::New(isolate, (int)length);
 	for(i=0; i<length; i++) {
-	    array->Set(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<Value> convert_ruby_to_v8(Isolate* isolate, VALUE value) {
 	length = RARRAY_LEN(hash_as_array);
 	for(i=0; i<length; i++) {
 	    pair = rb_ary_entry(hash_as_array, i);
-	    object->Set(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<Value> 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<Value> 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<v8::Context> context,
+                    const char *utf8_source, const char *name) {
+    Context::Scope context_scope(context);
+    TryCatch try_catch(isolate);
+    Local<String> source_string;
+    if (!String::NewFromUtf8(isolate, utf8_source,
+                             NewStringType::kNormal)
+             .ToLocal(&source_string)) {
+        return false;
+    }
+    Local<v8::String> resource_name =
+        String::NewFromUtf8(isolate, name, NewStringType::kNormal)
+            .ToLocalChecked();
+    ScriptOrigin origin(resource_name);
+    ScriptCompiler::Source source(source_string, origin);
+    Local<Script> script;
+    if (!ScriptCompiler::Compile(context, &source).ToLocal(&script))
+        return false;
+    if (script->Run(context).IsEmpty())
+        return false;
+    // CHECK(!try_catch.HasCaught());
+    return true;
+}
+
+StartupData
+create_snapshot_data_blob(const char *embedded_source = nullptr) {
+    // Create a new isolate and a new context from scratch, optionally run
+    // a script to embed, and serialize to create a snapshot blob.
+    StartupData result = {nullptr, 0};
+    {
+        SnapshotCreator snapshot_creator;

[... diff too long, it was truncated ...]

GitHub sha: a22348f7