summaryrefslogtreecommitdiff
path: root/chromium/v8/src/d8
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-10-26 13:57:00 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-11-02 11:31:01 +0000
commit1943b3c2a1dcee36c233724fc4ee7613d71b9cf6 (patch)
tree8c1b5f12357025c197da5427ae02cfdc2f3570d6 /chromium/v8/src/d8
parent21ba0c5d4bf8fba15dddd97cd693bad2358b77fd (diff)
downloadqtwebengine-chromium-1943b3c2a1dcee36c233724fc4ee7613d71b9cf6.tar.gz
BASELINE: Update Chromium to 94.0.4606.111
Change-Id: I924781584def20fc800bedf6ff41fdb96c438193 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/v8/src/d8')
-rw-r--r--chromium/v8/src/d8/OWNERS1
-rw-r--r--chromium/v8/src/d8/d8-platforms.cc16
-rw-r--r--chromium/v8/src/d8/d8-posix.cc4
-rw-r--r--chromium/v8/src/d8/d8-test.cc342
-rw-r--r--chromium/v8/src/d8/d8.cc548
-rw-r--r--chromium/v8/src/d8/d8.h79
6 files changed, 799 insertions, 191 deletions
diff --git a/chromium/v8/src/d8/OWNERS b/chromium/v8/src/d8/OWNERS
index a96bac9f5da..8d147e1642d 100644
--- a/chromium/v8/src/d8/OWNERS
+++ b/chromium/v8/src/d8/OWNERS
@@ -1,5 +1,4 @@
cbruni@chromium.org
clemensb@chromium.org
marja@chromium.org
-ulan@chromium.org
verwaest@chromium.org
diff --git a/chromium/v8/src/d8/d8-platforms.cc b/chromium/v8/src/d8/d8-platforms.cc
index 40cba2c69e2..722b2bc4e2e 100644
--- a/chromium/v8/src/d8/d8-platforms.cc
+++ b/chromium/v8/src/d8/d8-platforms.cc
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "src/d8/d8-platforms.h"
+
#include <memory>
#include <unordered_map>
+#include "include/libplatform/libplatform.h"
#include "include/v8-platform.h"
#include "src/base/logging.h"
#include "src/base/macros.h"
@@ -12,7 +15,6 @@
#include "src/base/platform/platform.h"
#include "src/base/platform/time.h"
#include "src/base/utils/random-number-generator.h"
-#include "src/d8/d8-platforms.h"
namespace v8 {
@@ -43,7 +45,12 @@ class PredictablePlatform final : public Platform {
return platform_->GetForegroundTaskRunner(isolate);
}
- int NumberOfWorkerThreads() override { return 0; }
+ int NumberOfWorkerThreads() override {
+ // The predictable platform executes everything on the main thread, but we
+ // still pretend to have the default number of worker threads to not
+ // unnecessarily change behaviour of the platform.
+ return platform_->NumberOfWorkerThreads();
+ }
void CallOnWorkerThread(std::unique_ptr<Task> task) override {
// We post worker tasks on the foreground task runner of the
@@ -68,7 +75,10 @@ class PredictablePlatform final : public Platform {
std::unique_ptr<JobHandle> PostJob(
TaskPriority priority, std::unique_ptr<JobTask> job_task) override {
- return platform_->PostJob(priority, std::move(job_task));
+ // Do not call {platform_->PostJob} here, as this would create a job that
+ // posts tasks directly to the underlying default platform.
+ return platform::NewDefaultJobHandle(this, priority, std::move(job_task),
+ NumberOfWorkerThreads());
}
double MonotonicallyIncreasingTime() override {
diff --git a/chromium/v8/src/d8/d8-posix.cc b/chromium/v8/src/d8/d8-posix.cc
index fa30b9153d4..05e475f5387 100644
--- a/chromium/v8/src/d8/d8-posix.cc
+++ b/chromium/v8/src/d8/d8-posix.cc
@@ -318,7 +318,7 @@ static Local<Value> GetStdout(Isolate* isolate, int child_fd,
.ToLocalChecked();
accumulator = String::Concat(isolate, accumulator, addition);
fullness = bytes_read + fullness - length;
- base::Memcpy(buffer, buffer + length, fullness);
+ memcpy(buffer, buffer + length, fullness);
}
} while (bytes_read != 0);
return accumulator;
@@ -343,7 +343,7 @@ static Local<Value> GetStdout(Isolate* isolate, int child_fd,
// Get exit status of child.
static bool WaitForChild(Isolate* isolate, int pid,
- ZombieProtector& child_waiter, // NOLINT
+ ZombieProtector& child_waiter,
const struct timeval& start_time, int read_timeout,
int total_timeout) {
#ifdef HAS_WAITID
diff --git a/chromium/v8/src/d8/d8-test.cc b/chromium/v8/src/d8/d8-test.cc
index 741b838b760..635a1f45141 100644
--- a/chromium/v8/src/d8/d8-test.cc
+++ b/chromium/v8/src/d8/d8-test.cc
@@ -5,6 +5,7 @@
#include "src/d8/d8.h"
#include "include/v8-fast-api-calls.h"
+#include "src/api/api-inl.h"
// This file exposes a d8.test.fast_c_api object, which adds testing facility
// for writing mjsunit tests that exercise fast API calls. The fast_c_api object
@@ -55,14 +56,6 @@ class FastCApiObject {
static_cast<double>(arg_i64) + static_cast<double>(arg_u64) +
static_cast<double>(arg_f32) + arg_f64;
}
- static double AddAllFastCallback_5Args(Local<Object> receiver,
- bool should_fallback, int32_t arg_i32,
- uint32_t arg_u32, int64_t arg_i64,
- uint64_t arg_u64, float arg_f32,
- FastApiCallbackOptions& options) {
- return AddAllFastCallback(receiver, should_fallback, arg_i32, arg_u32,
- arg_i64, arg_u64, arg_f32, 0, options);
- }
static void AddAllSlowCallback(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
@@ -99,6 +92,190 @@ class FastCApiObject {
args.GetReturnValue().Set(Number::New(isolate, sum));
}
+#ifdef V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
+ typedef double Type;
+ static constexpr CTypeInfo type_info = CTypeInfo(CTypeInfo::Type::kFloat64);
+#else
+ typedef int32_t Type;
+ static constexpr CTypeInfo type_info = CTypeInfo(CTypeInfo::Type::kInt32);
+#endif // V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
+ static Type AddAllSequenceFastCallback(Local<Object> receiver,
+ bool should_fallback,
+ Local<Array> seq_arg,
+ FastApiCallbackOptions& options) {
+ FastCApiObject* self = UnwrapObject(receiver);
+ CHECK_SELF_OR_FALLBACK(0);
+ self->fast_call_count_++;
+
+ if (should_fallback) {
+ options.fallback = 1;
+ return 0;
+ }
+
+ uint32_t length = seq_arg->Length();
+ if (length > 1024) {
+ options.fallback = 1;
+ return 0;
+ }
+
+ Type buffer[1024];
+ bool result = TryCopyAndConvertArrayToCppBuffer<&type_info, Type>(
+ seq_arg, buffer, 1024);
+ if (!result) {
+ options.fallback = 1;
+ return 0;
+ }
+ DCHECK_EQ(seq_arg->Length(), length);
+
+ Type sum = 0;
+ for (uint32_t i = 0; i < length; ++i) {
+ sum += buffer[i];
+ }
+
+ return sum;
+ }
+ static void AddAllSequenceSlowCallback(
+ const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+
+ FastCApiObject* self = UnwrapObject(args.This());
+ CHECK_SELF_OR_THROW();
+
+ HandleScope handle_scope(isolate);
+
+ if (args.Length() < 2) {
+ self->slow_call_count_++;
+ isolate->ThrowError("This method expects at least 2 arguments.");
+ return;
+ }
+ if (args[1]->IsTypedArray()) {
+ AddAllTypedArraySlowCallback(args);
+ return;
+ }
+ self->slow_call_count_++;
+ if (args[1]->IsUndefined()) {
+ Type dummy_result = 0;
+ args.GetReturnValue().Set(Number::New(isolate, dummy_result));
+ return;
+ }
+ if (!args[1]->IsArray()) {
+ isolate->ThrowError("This method expects an array as a second argument.");
+ return;
+ }
+
+ Local<Array> seq_arg = args[1].As<Array>();
+ uint32_t length = seq_arg->Length();
+ if (length > 1024) {
+ isolate->ThrowError(
+ "Invalid length of array, must be between 0 and 1024.");
+ return;
+ }
+
+ Type sum = 0;
+ for (uint32_t i = 0; i < length; ++i) {
+ v8::Local<v8::Value> element =
+ seq_arg
+ ->Get(isolate->GetCurrentContext(),
+ v8::Integer::NewFromUnsigned(isolate, i))
+ .ToLocalChecked();
+ if (element->IsNumber()) {
+ double value = element->ToNumber(isolate->GetCurrentContext())
+ .ToLocalChecked()
+ ->Value();
+ sum += value;
+ } else if (element->IsUndefined()) {
+ // Hole: ignore the element.
+ } else {
+ isolate->ThrowError("unexpected element type in JSArray");
+ return;
+ }
+ }
+ args.GetReturnValue().Set(Number::New(isolate, sum));
+ }
+ template <typename T>
+ static Type AddAllTypedArrayFastCallback(
+ Local<Object> receiver, bool should_fallback,
+ const FastApiTypedArray<T>& typed_array_arg,
+ FastApiCallbackOptions& options) {
+ FastCApiObject* self = UnwrapObject(receiver);
+ CHECK_SELF_OR_FALLBACK(0);
+ self->fast_call_count_++;
+
+ if (should_fallback) {
+ options.fallback = 1;
+ return 0;
+ }
+
+ T sum = 0;
+ for (unsigned i = 0; i < typed_array_arg.length(); ++i) {
+ sum += typed_array_arg.get(i);
+ }
+ return static_cast<Type>(sum);
+ }
+ static void AddAllTypedArraySlowCallback(
+ const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+
+ FastCApiObject* self = UnwrapObject(args.This());
+ CHECK_SELF_OR_THROW();
+ self->slow_call_count_++;
+
+ HandleScope handle_scope(isolate);
+
+ if (args.Length() < 2) {
+ isolate->ThrowError("This method expects at least 2 arguments.");
+ return;
+ }
+ if (!args[1]->IsTypedArray()) {
+ isolate->ThrowError(
+ "This method expects a TypedArray as a second argument.");
+ return;
+ }
+
+ Local<TypedArray> typed_array_arg = args[1].As<TypedArray>();
+ size_t length = typed_array_arg->Length();
+
+ void* data = typed_array_arg->Buffer()->GetBackingStore()->Data();
+ if (typed_array_arg->IsInt32Array() || typed_array_arg->IsUint32Array() ||
+ typed_array_arg->IsBigInt64Array() ||
+ typed_array_arg->IsBigUint64Array()) {
+ int64_t sum = 0;
+ for (unsigned i = 0; i < length; ++i) {
+ if (typed_array_arg->IsInt32Array()) {
+ sum += static_cast<int32_t*>(data)[i];
+ } else if (typed_array_arg->IsUint32Array()) {
+ sum += static_cast<uint32_t*>(data)[i];
+ } else if (typed_array_arg->IsBigInt64Array()) {
+ sum += static_cast<int64_t*>(data)[i];
+ } else if (typed_array_arg->IsBigUint64Array()) {
+ sum += static_cast<uint64_t*>(data)[i];
+ }
+ }
+ args.GetReturnValue().Set(Number::New(isolate, sum));
+ } else if (typed_array_arg->IsFloat32Array() ||
+ typed_array_arg->IsFloat64Array()) {
+ double sum = 0;
+ for (unsigned i = 0; i < length; ++i) {
+ if (typed_array_arg->IsFloat32Array()) {
+ sum += static_cast<float*>(data)[i];
+ } else if (typed_array_arg->IsFloat64Array()) {
+ sum += static_cast<double*>(data)[i];
+ }
+ }
+ args.GetReturnValue().Set(Number::New(isolate, sum));
+ } else {
+ isolate->ThrowError("TypedArray type is not supported.");
+ return;
+ }
+ }
+
+ static int32_t AddAllIntInvalidCallback(Local<Object> receiver,
+ bool should_fallback, int32_t arg_i32,
+ FastApiCallbackOptions& options) {
+ // This should never be called
+ UNREACHABLE();
+ }
+
static int Add32BitIntFastCallback(v8::Local<v8::Object> receiver,
bool should_fallback, int32_t arg_i32,
uint32_t arg_u32,
@@ -134,6 +311,66 @@ class FastCApiObject {
args.GetReturnValue().Set(Number::New(isolate, sum));
}
+ static int AddAll32BitIntFastCallback_6Args(
+ Local<Object> receiver, bool should_fallback, int32_t arg1_i32,
+ int32_t arg2_i32, int32_t arg3_i32, uint32_t arg4_u32, uint32_t arg5_u32,
+ uint32_t arg6_u32, FastApiCallbackOptions& options) {
+ FastCApiObject* self = UnwrapObject(receiver);
+ CHECK_SELF_OR_FALLBACK(0);
+ self->fast_call_count_++;
+
+ if (should_fallback) {
+ options.fallback = 1;
+ return 0;
+ }
+
+ int64_t result = static_cast<int64_t>(arg1_i32) + arg2_i32 + arg3_i32 +
+ arg4_u32 + arg5_u32 + arg6_u32;
+ if (result > INT_MAX) return INT_MAX;
+ if (result < INT_MIN) return INT_MIN;
+ return static_cast<int>(result);
+ }
+ static int AddAll32BitIntFastCallback_5Args(
+ Local<Object> receiver, bool should_fallback, int32_t arg1_i32,
+ int32_t arg2_i32, int32_t arg3_i32, uint32_t arg4_u32, uint32_t arg5_u32,
+ FastApiCallbackOptions& options) {
+ return AddAll32BitIntFastCallback_6Args(receiver, should_fallback, arg1_i32,
+ arg2_i32, arg3_i32, arg4_u32,
+ arg5_u32, 0, options);
+ }
+ static void AddAll32BitIntSlowCallback(
+ const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+
+ FastCApiObject* self = UnwrapObject(args.This());
+ CHECK_SELF_OR_THROW();
+ self->slow_call_count_++;
+
+ HandleScope handle_scope(isolate);
+
+ double sum = 0;
+ if (args.Length() > 1 && args[1]->IsNumber()) {
+ sum += args[1]->Int32Value(isolate->GetCurrentContext()).FromJust();
+ }
+ if (args.Length() > 2 && args[2]->IsNumber()) {
+ sum += args[2]->Int32Value(isolate->GetCurrentContext()).FromJust();
+ }
+ if (args.Length() > 3 && args[3]->IsNumber()) {
+ sum += args[3]->Int32Value(isolate->GetCurrentContext()).FromJust();
+ }
+ if (args.Length() > 4 && args[4]->IsNumber()) {
+ sum += args[4]->Uint32Value(isolate->GetCurrentContext()).FromJust();
+ }
+ if (args.Length() > 5 && args[5]->IsNumber()) {
+ sum += args[5]->Uint32Value(isolate->GetCurrentContext()).FromJust();
+ }
+ if (args.Length() > 6 && args[6]->IsNumber()) {
+ sum += args[6]->Uint32Value(isolate->GetCurrentContext()).FromJust();
+ }
+
+ args.GetReturnValue().Set(Number::New(isolate, sum));
+ }
+
static bool IsFastCApiObjectFastCallback(v8::Local<v8::Object> receiver,
bool should_fallback,
v8::Local<v8::Value> arg,
@@ -230,7 +467,8 @@ class FastCApiObject {
static bool IsValidApiObject(Local<Object> object) {
i::Address addr = *reinterpret_cast<i::Address*>(*object);
auto instance_type = i::Internals::GetInstanceType(addr);
- return (instance_type == i::Internals::kJSApiObjectType ||
+ return (base::IsInRange(instance_type, i::Internals::kFirstJSApiObjectType,
+ i::Internals::kLastJSApiObjectType) ||
instance_type == i::Internals::kJSSpecialApiObjectType);
}
static FastCApiObject* UnwrapObject(Local<Object> object) {
@@ -290,15 +528,87 @@ Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) {
ConstructorBehavior::kThrow,
SideEffectType::kHasSideEffect, &add_all_c_func));
- // To test function overloads.
- CFunction add_all_5args_c_func =
- CFunction::Make(FastCApiObject::AddAllFastCallback_5Args);
- const CFunction c_function_overloads[] = {add_all_c_func,
- add_all_5args_c_func};
+ CFunction add_all_seq_c_func =
+ CFunction::Make(FastCApiObject::AddAllSequenceFastCallback);
+ api_obj_ctor->PrototypeTemplate()->Set(
+ isolate, "add_all_sequence",
+ FunctionTemplate::New(
+ isolate, FastCApiObject::AddAllSequenceSlowCallback, Local<Value>(),
+ signature, 1, ConstructorBehavior::kThrow,
+ SideEffectType::kHasSideEffect, &add_all_seq_c_func));
+
+ CFunction add_all_int32_typed_array_c_func =
+ CFunction::Make(FastCApiObject::AddAllTypedArrayFastCallback<int32_t>);
+ api_obj_ctor->PrototypeTemplate()->Set(
+ isolate, "add_all_int32_typed_array",
+ FunctionTemplate::New(
+ isolate, FastCApiObject::AddAllTypedArraySlowCallback,
+ Local<Value>(), signature, 1, ConstructorBehavior::kThrow,
+ SideEffectType::kHasSideEffect, &add_all_int32_typed_array_c_func));
+
+ CFunction add_all_int64_typed_array_c_func =
+ CFunction::Make(FastCApiObject::AddAllTypedArrayFastCallback<int64_t>);
+ api_obj_ctor->PrototypeTemplate()->Set(
+ isolate, "add_all_int64_typed_array",
+ FunctionTemplate::New(
+ isolate, FastCApiObject::AddAllTypedArraySlowCallback,
+ Local<Value>(), signature, 1, ConstructorBehavior::kThrow,
+ SideEffectType::kHasSideEffect, &add_all_int64_typed_array_c_func));
+
+ CFunction add_all_uint64_typed_array_c_func =
+ CFunction::Make(FastCApiObject::AddAllTypedArrayFastCallback<uint64_t>);
+ api_obj_ctor->PrototypeTemplate()->Set(
+ isolate, "add_all_uint64_typed_array",
+ FunctionTemplate::New(
+ isolate, FastCApiObject::AddAllTypedArraySlowCallback,
+ Local<Value>(), signature, 1, ConstructorBehavior::kThrow,
+ SideEffectType::kHasSideEffect,
+ &add_all_uint64_typed_array_c_func));
+
+ CFunction add_all_uint32_typed_array_c_func =
+ CFunction::Make(FastCApiObject::AddAllTypedArrayFastCallback<uint32_t>);
+ api_obj_ctor->PrototypeTemplate()->Set(
+ isolate, "add_all_uint32_typed_array",
+ FunctionTemplate::New(
+ isolate, FastCApiObject::AddAllTypedArraySlowCallback,
+ Local<Value>(), signature, 1, ConstructorBehavior::kThrow,
+ SideEffectType::kHasSideEffect,
+ &add_all_uint32_typed_array_c_func));
+
+ const CFunction add_all_overloads[] = {
+ add_all_uint32_typed_array_c_func,
+ add_all_seq_c_func,
+ };
+ api_obj_ctor->PrototypeTemplate()->Set(
+ isolate, "add_all_overload",
+ FunctionTemplate::NewWithCFunctionOverloads(
+ isolate, FastCApiObject::AddAllSequenceSlowCallback, Local<Value>(),
+ signature, 1, ConstructorBehavior::kThrow,
+ SideEffectType::kHasSideEffect, {add_all_overloads, 2}));
+
+ CFunction add_all_int_invalid_func =
+ CFunction::Make(FastCApiObject::AddAllIntInvalidCallback);
+ const CFunction add_all_invalid_overloads[] = {
+ add_all_int_invalid_func,
+ add_all_seq_c_func,
+ };
+ api_obj_ctor->PrototypeTemplate()->Set(
+ isolate, "add_all_invalid_overload",
+ FunctionTemplate::NewWithCFunctionOverloads(
+ isolate, FastCApiObject::AddAllSequenceSlowCallback, Local<Value>(),
+ signature, 1, ConstructorBehavior::kThrow,
+ SideEffectType::kHasSideEffect, {add_all_invalid_overloads, 2}));
+
+ CFunction add_all_32bit_int_6args_c_func =
+ CFunction::Make(FastCApiObject::AddAll32BitIntFastCallback_6Args);
+ CFunction add_all_32bit_int_5args_c_func =
+ CFunction::Make(FastCApiObject::AddAll32BitIntFastCallback_5Args);
+ const CFunction c_function_overloads[] = {add_all_32bit_int_6args_c_func,
+ add_all_32bit_int_5args_c_func};
api_obj_ctor->PrototypeTemplate()->Set(
- isolate, "overloaded_add_all",
+ isolate, "overloaded_add_all_32bit_int",
FunctionTemplate::NewWithCFunctionOverloads(
- isolate, FastCApiObject::AddAllSlowCallback, Local<Value>(),
+ isolate, FastCApiObject::AddAll32BitIntSlowCallback, Local<Value>(),
signature, 1, ConstructorBehavior::kThrow,
SideEffectType::kHasSideEffect, {c_function_overloads, 2}));
diff --git a/chromium/v8/src/d8/d8.cc b/chromium/v8/src/d8/d8.cc
index 8c9a4c3ae60..2b831bc7473 100644
--- a/chromium/v8/src/d8/d8.cc
+++ b/chromium/v8/src/d8/d8.cc
@@ -34,6 +34,7 @@
#include "src/base/platform/wrappers.h"
#include "src/base/sanitizer/msan.h"
#include "src/base/sys-info.h"
+#include "src/base/utils/random-number-generator.h"
#include "src/d8/d8-console.h"
#include "src/d8/d8-platforms.h"
#include "src/d8/d8.h"
@@ -78,9 +79,9 @@
#endif
#if !defined(_WIN32) && !defined(_WIN64)
-#include <unistd.h> // NOLINT
+#include <unistd.h>
#else
-#include <windows.h> // NOLINT
+#include <windows.h>
#endif // !defined(_WIN32) && !defined(_WIN64)
#ifndef DCHECK
@@ -485,7 +486,7 @@ ScriptCompiler::CachedData* Shell::LookupCodeCache(Isolate* isolate,
if (entry != cached_code_map_.end() && entry->second) {
int length = entry->second->length;
uint8_t* cache = new uint8_t[length];
- base::Memcpy(cache, entry->second->data, length);
+ memcpy(cache, entry->second->data, length);
ScriptCompiler::CachedData* cached_data = new ScriptCompiler::CachedData(
cache, length, ScriptCompiler::CachedData::BufferOwned);
return cached_data;
@@ -502,7 +503,7 @@ void Shell::StoreInCodeCache(Isolate* isolate, Local<Value> source,
DCHECK(*key);
int length = cache_data->length;
uint8_t* cache = new uint8_t[length];
- base::Memcpy(cache, cache_data->data, length);
+ memcpy(cache, cache_data->data, length);
cached_code_map_[*key] = std::unique_ptr<ScriptCompiler::CachedData>(
new ScriptCompiler::CachedData(cache, length,
ScriptCompiler::CachedData::BufferOwned));
@@ -643,8 +644,8 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
Local<Value> name, PrintResult print_result,
ReportExceptions report_exceptions,
ProcessMessageQueue process_message_queue) {
+ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
if (i::FLAG_parse_only) {
- i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::VMState<PARSER> state(i_isolate);
i::Handle<i::String> str = Utils::OpenHandle(*(source));
@@ -654,7 +655,7 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForToplevelCompile(
i_isolate, true, i::construct_language_mode(i::FLAG_use_strict),
- i::REPLMode::kNo);
+ i::REPLMode::kNo, ScriptType::kClassic, i::FLAG_lazy);
if (options.compile_options == v8::ScriptCompiler::kEagerCompile) {
flags.set_is_eager(true);
@@ -680,6 +681,15 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
TryCatch try_catch(isolate);
try_catch.SetVerbose(report_exceptions == kReportExceptions);
+ // Explicitly check for stack overflows. This method can be called
+ // recursively, and since we consume quite some stack space for the C++
+ // frames, the stack check in the called frame might be too late.
+ if (i::StackLimitCheck{i_isolate}.HasOverflowed()) {
+ i_isolate->StackOverflow();
+ i_isolate->OptionalRescheduleException(false);
+ return false;
+ }
+
MaybeLocal<Value> maybe_result;
bool success = true;
{
@@ -730,8 +740,10 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
data->realm_current_ = data->realm_switch_;
if (options.web_snapshot_config) {
- std::vector<std::string> exports;
- if (!ReadLines(options.web_snapshot_config, exports)) {
+ MaybeLocal<PrimitiveArray> maybe_exports =
+ ReadLines(isolate, options.web_snapshot_config);
+ Local<PrimitiveArray> exports;
+ if (!maybe_exports.ToLocal(&exports)) {
isolate->ThrowError("Web snapshots: unable to read config");
CHECK(try_catch.HasCaught());
ReportException(isolate, &try_catch);
@@ -950,10 +962,10 @@ MaybeLocal<Module> Shell::FetchModuleTree(Local<Module> referrer,
ModuleType module_type) {
DCHECK(IsAbsolutePath(file_name));
Isolate* isolate = context->GetIsolate();
- Local<String> source_text = ReadFile(isolate, file_name.c_str());
+ Local<String> source_text = ReadFile(isolate, file_name.c_str(), false);
if (source_text.IsEmpty() && options.fuzzy_module_file_extensions) {
std::string fallback_file_name = file_name + ".js";
- source_text = ReadFile(isolate, fallback_file_name.c_str());
+ source_text = ReadFile(isolate, fallback_file_name.c_str(), false);
if (source_text.IsEmpty()) {
fallback_file_name = file_name + ".mjs";
source_text = ReadFile(isolate, fallback_file_name.c_str());
@@ -1386,6 +1398,10 @@ PerIsolateData::PerIsolateData(Isolate* isolate)
async_hooks_wrapper_ = new AsyncHooks(isolate);
}
ignore_unhandled_promises_ = false;
+ // TODO(v8:11525): Use methods on global Snapshot objects with
+ // signature checks.
+ HandleScope scope(isolate);
+ Shell::CreateSnapshotTemplate(isolate);
}
PerIsolateData::~PerIsolateData() {
@@ -1481,6 +1497,14 @@ void PerIsolateData::SetTestApiObjectCtor(Local<FunctionTemplate> ctor) {
test_api_object_ctor_.Reset(isolate_, ctor);
}
+Local<FunctionTemplate> PerIsolateData::GetSnapshotObjectCtor() const {
+ return snapshot_object_ctor_.Get(isolate_);
+}
+
+void PerIsolateData::SetSnapshotObjectCtor(Local<FunctionTemplate> ctor) {
+ snapshot_object_ctor_.Reset(isolate_, ctor);
+}
+
PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) {
data_->realm_count_ = 1;
data_->realm_current_ = 0;
@@ -1503,6 +1527,24 @@ PerIsolateData::RealmScope::~RealmScope() {
delete[] data_->realms_;
}
+PerIsolateData::ExplicitRealmScope::ExplicitRealmScope(PerIsolateData* data,
+ int index)
+ : data_(data), index_(index) {
+ realm_ = Local<Context>::New(data->isolate_, data->realms_[index_]);
+ realm_->Enter();
+ previous_index_ = data->realm_current_;
+ data->realm_current_ = data->realm_switch_ = index_;
+}
+
+PerIsolateData::ExplicitRealmScope::~ExplicitRealmScope() {
+ realm_->Exit();
+ data_->realm_current_ = data_->realm_switch_ = previous_index_;
+}
+
+Local<Context> PerIsolateData::ExplicitRealmScope::context() const {
+ return realm_;
+}
+
int PerIsolateData::RealmFind(Local<Context> context) {
for (int i = 0; i < realm_count_; ++i) {
if (realms_[i] == context) return i;
@@ -1550,8 +1592,11 @@ void Shell::PerformanceMeasureMemory(
Local<Object> object = args[0].As<Object>();
Local<Value> value = TryGetValue(isolate, context, object, "detailed")
.FromMaybe(Local<Value>());
- if (!value.IsEmpty() && value->IsBoolean() &&
- value->BooleanValue(isolate)) {
+ if (value.IsEmpty()) {
+ // Exception was thrown and scheduled, so return from the callback.
+ return;
+ }
+ if (value->IsBoolean() && value->BooleanValue(isolate)) {
mode = v8::MeasureMemoryMode::kDetailed;
}
}
@@ -1604,8 +1649,22 @@ void Shell::RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
PerIsolateData* data = PerIsolateData::Get(args.GetIsolate());
int index = data->RealmIndexOrThrow(args, 0);
if (index == -1) return;
- args.GetReturnValue().Set(
- Local<Context>::New(args.GetIsolate(), data->realms_[index])->Global());
+ // TODO(chromium:324812): Ideally Context::Global should never return raw
+ // global objects but return a global proxy. Currently it returns global
+ // object when the global proxy is detached from the global object. The
+ // following is a workaround till we fix Context::Global so we don't leak
+ // global objects.
+ Local<Object> global =
+ Local<Context>::New(args.GetIsolate(), data->realms_[index])->Global();
+ i::Handle<i::Object> i_global = Utils::OpenHandle(*global);
+ if (i_global->IsJSGlobalObject()) {
+ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
+ i::Handle<i::JSObject> i_global_proxy =
+ handle(i::Handle<i::JSGlobalObject>::cast(i_global)->global_proxy(),
+ i_isolate);
+ global = Utils::ToLocal(i_global_proxy);
+ }
+ args.GetReturnValue().Set(global);
}
MaybeLocal<Context> Shell::CreateRealm(
@@ -1741,32 +1800,34 @@ void Shell::RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
PerIsolateData* data = PerIsolateData::Get(isolate);
int index = data->RealmIndexOrThrow(args, 0);
if (index == -1) return;
- if (args.Length() < 2 || !args[1]->IsString()) {
- args.GetIsolate()->ThrowError("Invalid argument");
+ if (args.Length() < 2) {
+ isolate->ThrowError("Invalid argument");
+ return;
+ }
+
+ Local<String> source;
+ if (!ReadSource(args, 1, CodeType::kString).ToLocal(&source)) {
+ isolate->ThrowError("Invalid argument");
return;
}
ScriptOrigin origin(isolate,
String::NewFromUtf8Literal(isolate, "(d8)",
NewStringType::kInternalized));
- ScriptCompiler::Source script_source(
- args[1]->ToString(isolate->GetCurrentContext()).ToLocalChecked(), origin);
+ ScriptCompiler::Source script_source(source, origin);
Local<UnboundScript> script;
if (!ScriptCompiler::CompileUnboundScript(isolate, &script_source)
.ToLocal(&script)) {
return;
}
- Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
- realm->Enter();
- int previous_index = data->realm_current_;
- data->realm_current_ = data->realm_switch_ = index;
Local<Value> result;
- if (!script->BindToCurrentContext()->Run(realm).ToLocal(&result)) {
- realm->Exit();
- data->realm_current_ = data->realm_switch_ = previous_index;
- return;
+ {
+ PerIsolateData::ExplicitRealmScope realm_scope(data, index);
+ if (!script->BindToCurrentContext()
+ ->Run(realm_scope.context())
+ .ToLocal(&result)) {
+ return;
+ }
}
- realm->Exit();
- data->realm_current_ = data->realm_switch_ = previous_index;
args.GetReturnValue().Set(result);
}
@@ -1786,6 +1847,96 @@ void Shell::RealmSharedSet(Local<String> property, Local<Value> value,
data->realm_shared_.Reset(isolate, value);
}
+// Realm.takeWebSnapshot(index, exports) takes a snapshot of the list of exports
+// in the realm with the specified index and returns the result.
+void Shell::RealmTakeWebSnapshot(
+ const v8::FunctionCallbackInfo<v8::Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+ if (args.Length() < 2 || !args[1]->IsArray()) {
+ isolate->ThrowError("Invalid argument");
+ return;
+ }
+ PerIsolateData* data = PerIsolateData::Get(isolate);
+ int index = data->RealmIndexOrThrow(args, 0);
+ if (index == -1) return;
+ // Create a Local<PrimitiveArray> from the exports array.
+ Local<Context> current_context = isolate->GetCurrentContext();
+ Local<Array> exports_array = args[1].As<Array>();
+ int length = exports_array->Length();
+ Local<PrimitiveArray> exports = PrimitiveArray::New(isolate, length);
+ for (int i = 0; i < length; ++i) {
+ Local<Value> value;
+ Local<String> str;
+ if (!exports_array->Get(current_context, i).ToLocal(&value) ||
+ !value->ToString(current_context).ToLocal(&str) || str.IsEmpty()) {
+ isolate->ThrowError("Invalid argument");
+ return;
+ }
+ exports->Set(isolate, i, str);
+ }
+ // Take the snapshot in the specified Realm.
+ auto snapshot_data_shared = std::make_shared<i::WebSnapshotData>();
+ {
+ PerIsolateData::ExplicitRealmScope realm_scope(data, index);
+ i::WebSnapshotSerializer serializer(isolate);
+ if (!serializer.TakeSnapshot(realm_scope.context(), exports,
+ *snapshot_data_shared)) {
+ args.GetReturnValue().Set(Undefined(isolate));
+ return;
+ }
+ }
+ // Create a snapshot object and store the WebSnapshotData as an embedder
+ // field. TODO(v8:11525): Use methods on global Snapshot objects with
+ // signature checks.
+ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+ i::Handle<i::Object> snapshot_data_managed =
+ i::Managed<i::WebSnapshotData>::FromSharedPtr(
+ i_isolate, snapshot_data_shared->buffer_size, snapshot_data_shared);
+ v8::Local<v8::Value> shapshot_data = Utils::ToLocal(snapshot_data_managed);
+ Local<ObjectTemplate> snapshot_template =
+ data->GetSnapshotObjectCtor()->InstanceTemplate();
+ Local<Object> snapshot_instance =
+ snapshot_template->NewInstance(isolate->GetCurrentContext())
+ .ToLocalChecked();
+ snapshot_instance->SetInternalField(0, shapshot_data);
+ args.GetReturnValue().Set(snapshot_instance);
+}
+
+// Realm.useWebSnapshot(index, snapshot) deserializes the snapshot in the realm
+// with the specified index.
+void Shell::RealmUseWebSnapshot(
+ const v8::FunctionCallbackInfo<v8::Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+ if (args.Length() < 2 || !args[1]->IsObject()) {
+ isolate->ThrowError("Invalid argument");
+ return;
+ }
+ PerIsolateData* data = PerIsolateData::Get(isolate);
+ int index = data->RealmIndexOrThrow(args, 0);
+ if (index == -1) return;
+ // Restore the snapshot data from the snapshot object.
+ Local<Object> snapshot_instance = args[1].As<Object>();
+ Local<FunctionTemplate> snapshot_template = data->GetSnapshotObjectCtor();
+ if (!snapshot_template->HasInstance(snapshot_instance)) {
+ isolate->ThrowError("Invalid argument");
+ return;
+ }
+ v8::Local<v8::Value> snapshot_data = snapshot_instance->GetInternalField(0);
+ i::Handle<i::Object> snapshot_data_handle = Utils::OpenHandle(*snapshot_data);
+ auto snapshot_data_managed =
+ i::Handle<i::Managed<i::WebSnapshotData>>::cast(snapshot_data_handle);
+ std::shared_ptr<i::WebSnapshotData> snapshot_data_shared =
+ snapshot_data_managed->get();
+ // Deserialize the snapshot in the specified Realm.
+ {
+ PerIsolateData::ExplicitRealmScope realm_scope(data, index);
+ i::WebSnapshotDeserializer deserializer(isolate);
+ bool success = deserializer.UseWebSnapshot(
+ snapshot_data_shared->buffer, snapshot_data_shared->buffer_size);
+ args.GetReturnValue().Set(success);
+ }
+}
+
void Shell::LogGetAndStop(const v8::FunctionCallbackInfo<v8::Value>& args) {
Isolate* isolate = args.GetIsolate();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
@@ -1943,11 +2094,14 @@ void Shell::AsyncHooksTriggerAsyncId(
void Shell::SetPromiseHooks(const v8::FunctionCallbackInfo<v8::Value>& args) {
Isolate* isolate = args.GetIsolate();
if (i::FLAG_correctness_fuzzer_suppressions) {
- // Make sure we have no pending promises if correctness fuzzing is active.
- // Due to fast-paths we might have not created all intermediate promises
- // that aren't spec visible. However, the promise hook might expose them
- // and cause different output.
- isolate->PerformMicrotaskCheckpoint();
+ // Setting promise hoooks dynamically has unexpected timing side-effects
+ // with certain promise optimizations. We might not get all callbacks for
+ // previously scheduled Promises or optimized code-paths that skip Promise
+ // creation.
+ isolate->ThrowError(
+ "d8.promise.setHooks is disabled with "
+ "--correctness-fuzzer-suppressions");
+ return;
}
Local<Context> context = isolate->GetCurrentContext();
HandleScope handle_scope(isolate);
@@ -2006,14 +2160,14 @@ void Shell::PrintErr(const v8::FunctionCallbackInfo<v8::Value>& args) {
WriteAndFlush(stderr, args);
}
-void Shell::Write(const v8::FunctionCallbackInfo<v8::Value>& args) {
+void Shell::WriteStdout(const v8::FunctionCallbackInfo<v8::Value>& args) {
WriteToFile(stdout, args);
}
-void Shell::Read(const v8::FunctionCallbackInfo<v8::Value>& args) {
- String::Utf8Value file(args.GetIsolate(), args[0]);
- if (*file == nullptr) {
- args.GetIsolate()->ThrowError("Error loading file");
+void Shell::ReadFile(const v8::FunctionCallbackInfo<v8::Value>& args) {
+ String::Utf8Value file_name(args.GetIsolate(), args[0]);
+ if (*file_name == nullptr) {
+ args.GetIsolate()->ThrowError("Error converting filename to string");
return;
}
if (args.Length() == 2) {
@@ -2023,11 +2177,8 @@ void Shell::Read(const v8::FunctionCallbackInfo<v8::Value>& args) {
return;
}
}
- Local<String> source = ReadFile(args.GetIsolate(), *file);
- if (source.IsEmpty()) {
- args.GetIsolate()->ThrowError("Error loading file");
- return;
- }
+ Local<String> source = ReadFile(args.GetIsolate(), *file_name);
+ if (source.IsEmpty()) return;
args.GetReturnValue().Set(source);
}
@@ -2068,26 +2219,30 @@ Local<String> Shell::ReadFromStdin(Isolate* isolate) {
}
}
-void Shell::Load(const v8::FunctionCallbackInfo<v8::Value>& args) {
+void Shell::ExecuteFile(const v8::FunctionCallbackInfo<v8::Value>& args) {
+ Isolate* isolate = args.GetIsolate();
for (int i = 0; i < args.Length(); i++) {
- HandleScope handle_scope(args.GetIsolate());
- String::Utf8Value file(args.GetIsolate(), args[i]);
- if (*file == nullptr) {
- args.GetIsolate()->ThrowError("Error loading file");
- return;
- }
- Local<String> source = ReadFile(args.GetIsolate(), *file);
- if (source.IsEmpty()) {
- args.GetIsolate()->ThrowError("Error loading file");
+ HandleScope handle_scope(isolate);
+ String::Utf8Value file_name(isolate, args[i]);
+ if (*file_name == nullptr) {
+ std::ostringstream oss;
+ oss << "Cannot convert file[" << i << "] name to string.";
+ isolate->ThrowError(
+ String::NewFromUtf8(isolate, oss.str().c_str()).ToLocalChecked());
return;
}
+ Local<String> source = ReadFile(isolate, *file_name);
+ if (source.IsEmpty()) return;
if (!ExecuteString(
args.GetIsolate(), source,
- String::NewFromUtf8(args.GetIsolate(), *file).ToLocalChecked(),
+ String::NewFromUtf8(isolate, *file_name).ToLocalChecked(),
kNoPrintResult,
options.quiet_load ? kNoReportExceptions : kReportExceptions,
kNoProcessMessageQueue)) {
- args.GetIsolate()->ThrowError("Error executing file");
+ std::ostringstream oss;
+ oss << "Error executing file: \"" << *file_name << '"';
+ isolate->ThrowError(
+ String::NewFromUtf8(isolate, oss.str().c_str()).ToLocalChecked());
return;
}
}
@@ -2102,35 +2257,33 @@ void Shell::SetTimeout(const v8::FunctionCallbackInfo<v8::Value>& args) {
PerIsolateData::Get(isolate)->SetTimeout(callback, context);
}
-enum WorkerType { kClassic, kString, kFunction, kInvalid, kNone };
-
-void ReadWorkerTypeAndArguments(const v8::FunctionCallbackInfo<v8::Value>& args,
- WorkerType* worker_type,
- Local<Value>* arguments = nullptr) {
+void Shell::ReadCodeTypeAndArguments(
+ const v8::FunctionCallbackInfo<v8::Value>& args, int index,
+ CodeType* code_type, Local<Value>* arguments) {
Isolate* isolate = args.GetIsolate();
- if (args.Length() > 1 && args[1]->IsObject()) {
- Local<Object> object = args[1].As<Object>();
+ if (args.Length() > index && args[index]->IsObject()) {
+ Local<Object> object = args[index].As<Object>();
Local<Context> context = isolate->GetCurrentContext();
Local<Value> value;
if (!TryGetValue(isolate, context, object, "type").ToLocal(&value)) {
- *worker_type = WorkerType::kNone;
+ *code_type = CodeType::kNone;
return;
}
if (!value->IsString()) {
- *worker_type = WorkerType::kInvalid;
+ *code_type = CodeType::kInvalid;
return;
}
Local<String> worker_type_string =
value->ToString(context).ToLocalChecked();
String::Utf8Value str(isolate, worker_type_string);
- if (strcmp("string", *str) == 0) {
- *worker_type = WorkerType::kString;
- } else if (strcmp("classic", *str) == 0) {
- *worker_type = WorkerType::kClassic;
+ if (strcmp("classic", *str) == 0) {
+ *code_type = CodeType::kFileName;
+ } else if (strcmp("string", *str) == 0) {
+ *code_type = CodeType::kString;
} else if (strcmp("function", *str) == 0) {
- *worker_type = WorkerType::kFunction;
+ *code_type = CodeType::kFunction;
} else {
- *worker_type = WorkerType::kInvalid;
+ *code_type = CodeType::kInvalid;
}
if (arguments != nullptr) {
bool got_arguments =
@@ -2138,13 +2291,14 @@ void ReadWorkerTypeAndArguments(const v8::FunctionCallbackInfo<v8::Value>& args,
USE(got_arguments);
}
} else {
- *worker_type = WorkerType::kNone;
+ *code_type = CodeType::kNone;
}
}
-bool FunctionAndArgumentsToString(Local<Function> function,
- Local<Value> arguments, Local<String>* source,
- Isolate* isolate) {
+bool Shell::FunctionAndArgumentsToString(Local<Function> function,
+ Local<Value> arguments,
+ Local<String>* source,
+ Isolate* isolate) {
Local<Context> context = isolate->GetCurrentContext();
MaybeLocal<String> maybe_function_string =
function->FunctionProtoToString(context);
@@ -2187,6 +2341,54 @@ bool FunctionAndArgumentsToString(Local<Function> function,
return true;
}
+// ReadSource() supports reading source code through `args[index]` as specified
+// by the `default_type` or an optional options bag provided in `args[index+1]`
+// (e.g. `options={type: 'code_type', arguments:[...]}`).
+MaybeLocal<String> Shell::ReadSource(
+ const v8::FunctionCallbackInfo<v8::Value>& args, int index,
+ CodeType default_type) {
+ CodeType code_type;
+ Local<Value> arguments;
+ ReadCodeTypeAndArguments(args, index + 1, &code_type, &arguments);
+
+ Isolate* isolate = args.GetIsolate();
+ Local<String> source;
+ if (code_type == CodeType::kNone) {
+ code_type = default_type;
+ }
+ switch (code_type) {
+ case CodeType::kFunction:
+ if (!args[index]->IsFunction()) {
+ return MaybeLocal<String>();
+ }
+ // Source: ( function_to_string )( params )
+ if (!FunctionAndArgumentsToString(args[index].As<Function>(), arguments,
+ &source, isolate)) {
+ return MaybeLocal<String>();
+ }
+ break;
+ case CodeType::kFileName: {
+ if (!args[index]->IsString()) {
+ return MaybeLocal<String>();
+ }
+ String::Utf8Value filename(isolate, args[index]);
+ source = Shell::ReadFile(isolate, *filename);
+ if (source.IsEmpty()) return MaybeLocal<String>();
+ break;
+ }
+ case CodeType::kString:
+ if (!args[index]->IsString()) {
+ return MaybeLocal<String>();
+ }
+ source = args[index].As<String>();
+ break;
+ case CodeType::kNone:
+ case CodeType::kInvalid:
+ return MaybeLocal<String>();
+ }
+ return source;
+}
+
void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
Isolate* isolate = args.GetIsolate();
HandleScope handle_scope(isolate);
@@ -2196,48 +2398,9 @@ void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
}
Local<String> source;
- if (args[0]->IsFunction()) {
- // d8 supports `options={type: 'function', arguments:[...]}`, which means
- // the first argument is a function with the code to be ran. Restrictions
- // apply; in particular the function will be converted to a string and the
- // Worker constructed based on it.
- WorkerType worker_type;
- Local<Value> arguments;
- ReadWorkerTypeAndArguments(args, &worker_type, &arguments);
- if (worker_type != WorkerType::kFunction) {
- isolate->ThrowError("Invalid or missing worker type");
- return;
- }
-
- // Source: ( function_to_string )( params )
- if (!FunctionAndArgumentsToString(args[0].As<Function>(), arguments,
- &source, isolate)) {
- return;
- }
- } else {
- // d8 honors `options={type: 'string'}`, which means the first argument is
- // not a filename but string of script to be run.
- bool load_from_file = true;
- WorkerType worker_type;
- ReadWorkerTypeAndArguments(args, &worker_type);
- if (worker_type == WorkerType::kString) {
- load_from_file = false;
- } else if (worker_type != WorkerType::kNone &&
- worker_type != WorkerType::kClassic) {
- isolate->ThrowError("Invalid worker type");
- return;
- }
-
- if (load_from_file) {
- String::Utf8Value filename(isolate, args[0]);
- source = ReadFile(isolate, *filename);
- if (source.IsEmpty()) {
- args.GetIsolate()->ThrowError("Error loading worker script");
- return;
- }
- } else {
- source = args[0].As<String>();
- }
+ if (!ReadSource(args, 0, CodeType::kFileName).ToLocal(&source)) {
+ isolate->ThrowError("Invalid argument");
+ return;
}
if (!args.IsConstructCall()) {
@@ -2629,13 +2792,16 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
global_template->Set(isolate, "print", FunctionTemplate::New(isolate, Print));
global_template->Set(isolate, "printErr",
FunctionTemplate::New(isolate, PrintErr));
- global_template->Set(isolate, "write", FunctionTemplate::New(isolate, Write));
- global_template->Set(isolate, "read", FunctionTemplate::New(isolate, Read));
+ global_template->Set(isolate, "write",
+ FunctionTemplate::New(isolate, WriteStdout));
+ global_template->Set(isolate, "read",
+ FunctionTemplate::New(isolate, ReadFile));
global_template->Set(isolate, "readbuffer",
FunctionTemplate::New(isolate, ReadBuffer));
global_template->Set(isolate, "readline",
FunctionTemplate::New(isolate, ReadLine));
- global_template->Set(isolate, "load", FunctionTemplate::New(isolate, Load));
+ global_template->Set(isolate, "load",
+ FunctionTemplate::New(isolate, ExecuteFile));
global_template->Set(isolate, "setTimeout",
FunctionTemplate::New(isolate, SetTimeout));
// Some Emscripten-generated code tries to call 'quit', which in turn would
@@ -2675,6 +2841,13 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
Local<ObjectTemplate> Shell::CreateOSTemplate(Isolate* isolate) {
Local<ObjectTemplate> os_template = ObjectTemplate::New(isolate);
AddOSMethods(isolate, os_template);
+ os_template->Set(isolate, "name",
+ v8::String::NewFromUtf8Literal(isolate, V8_TARGET_OS_STRING),
+ PropertyAttribute::ReadOnly);
+ os_template->Set(
+ isolate, "d8Path",
+ v8::String::NewFromUtf8(isolate, options.d8_path).ToLocalChecked(),
+ PropertyAttribute::ReadOnly);
return os_template;
}
@@ -2768,18 +2941,39 @@ Local<ObjectTemplate> Shell::CreateRealmTemplate(Isolate* isolate) {
FunctionTemplate::New(isolate, RealmEval));
realm_template->SetAccessor(String::NewFromUtf8Literal(isolate, "shared"),
RealmSharedGet, RealmSharedSet);
+ if (options.d8_web_snapshot_api) {
+ realm_template->Set(isolate, "takeWebSnapshot",
+ FunctionTemplate::New(isolate, RealmTakeWebSnapshot));
+ realm_template->Set(isolate, "useWebSnapshot",
+ FunctionTemplate::New(isolate, RealmUseWebSnapshot));
+ }
return realm_template;
}
+Local<FunctionTemplate> Shell::CreateSnapshotTemplate(Isolate* isolate) {
+ Local<FunctionTemplate> snapshot_template = FunctionTemplate::New(isolate);
+ snapshot_template->InstanceTemplate()->SetInternalFieldCount(1);
+ PerIsolateData::Get(isolate)->SetSnapshotObjectCtor(snapshot_template);
+ return snapshot_template;
+}
Local<ObjectTemplate> Shell::CreateD8Template(Isolate* isolate) {
Local<ObjectTemplate> d8_template = ObjectTemplate::New(isolate);
{
+ Local<ObjectTemplate> file_template = ObjectTemplate::New(isolate);
+ file_template->Set(isolate, "read",
+ FunctionTemplate::New(isolate, Shell::ReadFile));
+ file_template->Set(isolate, "execute",
+ FunctionTemplate::New(isolate, Shell::ExecuteFile));
+ d8_template->Set(isolate, "file", file_template);
+ }
+ {
Local<ObjectTemplate> log_template = ObjectTemplate::New(isolate);
log_template->Set(isolate, "getAndStop",
FunctionTemplate::New(isolate, LogGetAndStop));
d8_template->Set(isolate, "log", log_template);
-
+ }
+ {
Local<ObjectTemplate> dom_template = ObjectTemplate::New(isolate);
dom_template->Set(isolate, "Div", Shell::CreateNodeTemplates(isolate));
d8_template->Set(isolate, "dom", dom_template);
@@ -2932,6 +3126,11 @@ void Shell::Initialize(Isolate* isolate, D8Console* console,
debug::SetConsoleDelegate(isolate, console);
}
+Local<String> Shell::WasmLoadSourceMapCallback(Isolate* isolate,
+ const char* path) {
+ return Shell::ReadFile(isolate, path, false);
+}
+
Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
// This needs to be a critical section since this is not thread-safe
base::MutexGuard lock_guard(context_mutex_.Pointer());
@@ -2941,7 +3140,7 @@ Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
Local<Context> context = Context::New(isolate, nullptr, global_template);
DCHECK(!context.IsEmpty());
if (i::FLAG_perf_prof_annotate_wasm || i::FLAG_vtune_prof_annotate_wasm) {
- isolate->SetWasmLoadSourceMapCallback(ReadFile);
+ isolate->SetWasmLoadSourceMapCallback(Shell::WasmLoadSourceMapCallback);
}
InitializeModuleEmbedderData(context);
if (options.include_arguments) {
@@ -3247,18 +3446,33 @@ char* Shell::ReadChars(const char* name, int* size_out) {
return chars;
}
-bool Shell::ReadLines(const char* name, std::vector<std::string>& lines) {
+MaybeLocal<PrimitiveArray> Shell::ReadLines(Isolate* isolate,
+ const char* name) {
int length;
const char* data = reinterpret_cast<const char*>(ReadChars(name, &length));
if (data == nullptr) {
- return false;
+ return MaybeLocal<PrimitiveArray>();
}
std::stringstream stream(data);
std::string line;
+ std::vector<std::string> lines;
while (std::getline(stream, line, '\n')) {
lines.emplace_back(line);
}
- return true;
+ // Create a Local<PrimitiveArray> off the read lines.
+ int size = static_cast<int>(lines.size());
+ Local<PrimitiveArray> exports = PrimitiveArray::New(isolate, size);
+ for (int i = 0; i < size; ++i) {
+ MaybeLocal<String> maybe_str = v8::String::NewFromUtf8(
+ isolate, lines[i].c_str(), NewStringType::kNormal,
+ static_cast<int>(lines[i].length()));
+ Local<String> str;
+ if (!maybe_str.ToLocal(&str)) {
+ return MaybeLocal<PrimitiveArray>();
+ }
+ exports->Set(isolate, i, str);
+ }
+ return exports;
}
void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args) {
@@ -3291,11 +3505,20 @@ void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args) {
}
// Reads a file into a v8 string.
-Local<String> Shell::ReadFile(Isolate* isolate, const char* name) {
+Local<String> Shell::ReadFile(Isolate* isolate, const char* name,
+ bool should_throw) {
std::unique_ptr<base::OS::MemoryMappedFile> file(
base::OS::MemoryMappedFile::open(
name, base::OS::MemoryMappedFile::FileMode::kReadOnly));
- if (!file) return Local<String>();
+ if (!file) {
+ if (should_throw) {
+ std::ostringstream oss;
+ oss << "Error loading file: \"" << name << '"';
+ isolate->ThrowError(
+ v8::String::NewFromUtf8(isolate, oss.str().c_str()).ToLocalChecked());
+ }
+ return Local<String>();
+ }
int size = static_cast<int>(file->size());
char* chars = static_cast<char*>(file->memory());
@@ -3593,7 +3816,7 @@ bool SourceGroup::Execute(Isolate* isolate) {
HandleScope handle_scope(isolate);
Local<String> file_name =
String::NewFromUtf8(isolate, arg).ToLocalChecked();
- Local<String> source = ReadFile(isolate, arg);
+ Local<String> source = Shell::ReadFile(isolate, arg);
if (source.IsEmpty()) {
printf("Error reading '%s'\n", arg);
base::OS::ExitProcess(1);
@@ -3610,10 +3833,6 @@ bool SourceGroup::Execute(Isolate* isolate) {
return success;
}
-Local<String> SourceGroup::ReadFile(Isolate* isolate, const char* name) {
- return Shell::ReadFile(isolate, name);
-}
-
SourceGroup::IsolateThread::IsolateThread(SourceGroup* group)
: base::Thread(GetThreadOptions("IsolateThread")), group_(group) {}
@@ -3908,7 +4127,7 @@ void Worker::ExecuteInThread() {
NewStringType::kInternalized));
Local<Value> onmessage;
if (maybe_onmessage.ToLocal(&onmessage) && onmessage->IsFunction()) {
- // Now wait for messages
+ // Now wait for messages.
ProcessMessages();
}
}
@@ -3961,6 +4180,7 @@ void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) {
bool Shell::SetOptions(int argc, char* argv[]) {
bool logfile_per_isolate = false;
bool no_always_opt = false;
+ options.d8_path = argv[0];
for (int i = 0; i < argc; i++) {
if (strcmp(argv[i], "--") == 0) {
argv[i] = nullptr;
@@ -4120,6 +4340,9 @@ bool Shell::SetOptions(int argc, char* argv[]) {
} else if (strncmp(argv[i], "--web-snapshot-config=", 22) == 0) {
options.web_snapshot_config = argv[i] + 22;
argv[i] = nullptr;
+ } else if (strcmp(argv[i], "--experimental-d8-web-snapshot-api") == 0) {
+ options.d8_web_snapshot_api = true;
+ argv[i] = nullptr;
} else if (strcmp(argv[i], "--compile-only") == 0) {
options.compile_only = true;
argv[i] = nullptr;
@@ -4141,6 +4364,8 @@ bool Shell::SetOptions(int argc, char* argv[]) {
} else if (strcmp(argv[i], "--enable-system-instrumentation") == 0) {
options.enable_system_instrumentation = true;
options.trace_enabled = true;
+ // This needs to be manually triggered for JIT ETW events to work.
+ i::FLAG_enable_system_instrumentation = true;
#if defined(V8_OS_WIN)
// Guard this bc the flag has a lot of overhead and is not currently used
// by macos
@@ -4148,6 +4373,14 @@ bool Shell::SetOptions(int argc, char* argv[]) {
#endif
argv[i] = nullptr;
#endif
+#if V8_ENABLE_WEBASSEMBLY
+ } else if (strcmp(argv[i], "--wasm-trap-handler") == 0) {
+ options.wasm_trap_handler = true;
+ argv[i] = nullptr;
+ } else if (strcmp(argv[i], "--no-wasm-trap-handler") == 0) {
+ options.wasm_trap_handler = false;
+ argv[i] = nullptr;
+#endif // V8_ENABLE_WEBASSEMBLY
}
}
@@ -4220,6 +4453,7 @@ int Shell::RunMain(Isolate* isolate, bool last_run) {
}
HandleScope scope(isolate);
Local<Context> context = CreateEvaluationContext(isolate);
+ CreateSnapshotTemplate(isolate);
bool use_existing_context = last_run && use_interactive_shell();
if (use_existing_context) {
// Keep using the same context in the interactive shell.
@@ -4328,18 +4562,22 @@ bool ProcessMessages(
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::SaveAndSwitchContext saved_context(i_isolate, i::Context());
SealHandleScope shs(isolate);
- while (v8::platform::PumpMessageLoop(g_default_platform, isolate,
- behavior())) {
- MicrotasksScope::PerformCheckpoint(isolate);
-
+ for (bool ran_tasks = true; ran_tasks;) {
+ // Execute one foreground task (if one exists), then microtasks.
+ ran_tasks = v8::platform::PumpMessageLoop(g_default_platform, isolate,
+ behavior());
+ if (ran_tasks) MicrotasksScope::PerformCheckpoint(isolate);
+
+ // In predictable mode we push all background tasks into the foreground
+ // task queue of the {kProcessGlobalPredictablePlatformWorkerTaskQueue}
+ // isolate. We execute all background tasks after running one foreground
+ // task.
if (i::FLAG_verify_predictable) {
- // In predictable mode we push all background tasks into the foreground
- // task queue of the {kProcessGlobalPredictablePlatformWorkerTaskQueue}
- // isolate. We execute the tasks after one foreground task has been
- // executed.
while (v8::platform::PumpMessageLoop(
g_default_platform,
- kProcessGlobalPredictablePlatformWorkerTaskQueue, behavior())) {
+ kProcessGlobalPredictablePlatformWorkerTaskQueue,
+ platform::MessageLoopBehavior::kDoNotWait)) {
+ ran_tasks = true;
}
}
}
@@ -4348,13 +4586,9 @@ bool ProcessMessages(
50.0 / base::Time::kMillisecondsPerSecond);
}
bool ran_set_timeout = false;
- if (!RunSetTimeoutCallback(isolate, &ran_set_timeout)) {
- return false;
- }
-
+ if (!RunSetTimeoutCallback(isolate, &ran_set_timeout)) return false;
if (!ran_set_timeout) return true;
}
- return true;
}
} // anonymous namespace
@@ -4369,6 +4603,17 @@ bool Shell::CompleteMessageLoop(Isolate* isolate) {
return should_wait ? platform::MessageLoopBehavior::kWaitForWork
: platform::MessageLoopBehavior::kDoNotWait;
};
+ if (i::FLAG_verify_predictable) {
+ bool ran_tasks = ProcessMessages(
+ isolate, [] { return platform::MessageLoopBehavior::kDoNotWait; });
+ if (get_waiting_behaviour() ==
+ platform::MessageLoopBehavior::kWaitForWork) {
+ FATAL(
+ "There is outstanding work after executing all tasks in predictable "
+ "mode -- this would deadlock.");
+ }
+ return ran_tasks;
+ }
return ProcessMessages(isolate, get_waiting_behaviour);
}
@@ -4841,9 +5086,9 @@ int Shell::Main(int argc, char* argv[]) {
}
#if V8_ENABLE_WEBASSEMBLY
- if (V8_TRAP_HANDLER_SUPPORTED && i::FLAG_wasm_trap_handler) {
- constexpr bool use_default_trap_handler = true;
- if (!v8::V8::EnableWebAssemblyTrapHandler(use_default_trap_handler)) {
+ if (V8_TRAP_HANDLER_SUPPORTED && options.wasm_trap_handler) {
+ constexpr bool kUseDefaultTrapHandler = true;
+ if (!v8::V8::EnableWebAssemblyTrapHandler(kUseDefaultTrapHandler)) {
FATAL("Could not register trap handler");
}
}
@@ -4960,8 +5205,7 @@ int Shell::Main(int argc, char* argv[]) {
RunShell(isolate);
}
- if (i::FLAG_trace_ignition_dispatches &&
- i::FLAG_trace_ignition_dispatches_output_file != nullptr) {
+ if (i::FLAG_trace_ignition_dispatches_output_file != nullptr) {
WriteIgnitionDispatchCountersFile(isolate);
}
@@ -5035,9 +5279,7 @@ int Shell::Main(int argc, char* argv[]) {
} // namespace v8
-#ifndef GOOGLE3
int main(int argc, char* argv[]) { return v8::Shell::Main(argc, argv); }
-#endif
#undef CHECK
#undef DCHECK
diff --git a/chromium/v8/src/d8/d8.h b/chromium/v8/src/d8/d8.h
index 75c80461156..9d3cc4f6d2e 100644
--- a/chromium/v8/src/d8/d8.h
+++ b/chromium/v8/src/d8/d8.h
@@ -115,7 +115,6 @@ class SourceGroup {
base::Thread* thread_;
void ExitShell(int exit_code);
- Local<String> ReadFile(Isolate* isolate, const char* name);
const char** argv_;
int begin_offset_;
@@ -255,6 +254,22 @@ class PerIsolateData {
PerIsolateData* data_;
};
+ // Contrary to RealmScope (which creates a new Realm), ExplicitRealmScope
+ // allows for entering an existing Realm, as specified by its index.
+ class V8_NODISCARD ExplicitRealmScope {
+ public:
+ explicit ExplicitRealmScope(PerIsolateData* data, int index);
+ ~ExplicitRealmScope();
+
+ Local<Context> context() const;
+
+ private:
+ PerIsolateData* data_;
+ Local<Context> realm_;
+ int index_;
+ int previous_index_;
+ };
+
inline void SetTimeout(Local<Function> callback, Local<Context> context);
inline MaybeLocal<Function> GetTimeoutCallback();
inline MaybeLocal<Context> GetTimeoutContext();
@@ -274,6 +289,9 @@ class PerIsolateData {
Local<FunctionTemplate> GetTestApiObjectCtor() const;
void SetTestApiObjectCtor(Local<FunctionTemplate> ctor);
+ Local<FunctionTemplate> GetSnapshotObjectCtor() const;
+ void SetSnapshotObjectCtor(Local<FunctionTemplate> ctor);
+
private:
friend class Shell;
friend class RealmScope;
@@ -293,6 +311,7 @@ class PerIsolateData {
std::unordered_set<DynamicImportData*> import_data_;
#endif
Global<FunctionTemplate> test_api_object_ctor_;
+ Global<FunctionTemplate> snapshot_object_ctor_;
int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args,
int arg_offset);
@@ -322,7 +341,7 @@ class ShellOptions {
DisallowReassignment(const char* name, T value)
: name_(name), value_(value) {}
- operator T() const { return value_; } // NOLINT
+ operator T() const { return value_; }
T get() const { return value_; }
DisallowReassignment& operator=(T value) {
if (check_d8_flag_contradictions) {
@@ -348,6 +367,7 @@ class ShellOptions {
bool specified_ = false;
};
+ DisallowReassignment<const char*> d8_path = {"d8-path", ""};
DisallowReassignment<bool> fuzzilli_coverage_statistics = {
"fuzzilli-coverage-statistics", false};
DisallowReassignment<bool> fuzzilli_enable_builtins_coverage = {
@@ -406,8 +426,13 @@ class ShellOptions {
"enable-system-instrumentation", false};
DisallowReassignment<const char*> web_snapshot_config = {
"web-snapshot-config", nullptr};
+ DisallowReassignment<bool> d8_web_snapshot_api = {
+ "experimental-d8-web-snapshot-api", false};
DisallowReassignment<bool> compile_only = {"compile-only", false};
DisallowReassignment<int> repeat_compile = {"repeat-compile", 1};
+#if V8_ENABLE_WEBASSEMBLY
+ DisallowReassignment<bool> wasm_trap_handler = {"wasm-trap-handler", true};
+#endif // V8_ENABLE_WEBASSEMBLY
};
class Shell : public i::AllStatic {
@@ -421,6 +446,7 @@ class Shell : public i::AllStatic {
kProcessMessageQueue = true,
kNoProcessMessageQueue = false
};
+ enum class CodeType { kFileName, kString, kFunction, kInvalid, kNone };
static bool ExecuteString(Isolate* isolate, Local<String> source,
Local<Value> name, PrintResult print_result,
@@ -431,7 +457,10 @@ class Shell : public i::AllStatic {
static void ReportException(Isolate* isolate, Local<Message> message,
Local<Value> exception);
static void ReportException(Isolate* isolate, TryCatch* try_catch);
- static Local<String> ReadFile(Isolate* isolate, const char* name);
+ static Local<String> ReadFile(Isolate* isolate, const char* name,
+ bool should_throw = true);
+ static Local<String> WasmLoadSourceMapCallback(Isolate* isolate,
+ const char* name);
static Local<Context> CreateEvaluationContext(Isolate* isolate);
static int RunMain(Isolate* isolate, bool last_run);
static int Main(int argc, char* argv[]);
@@ -476,6 +505,10 @@ class Shell : public i::AllStatic {
const PropertyCallbackInfo<Value>& info);
static void RealmSharedSet(Local<String> property, Local<Value> value,
const PropertyCallbackInfo<void>& info);
+ static void RealmTakeWebSnapshot(
+ const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void RealmUseWebSnapshot(
+ const v8::FunctionCallbackInfo<v8::Value>& args);
static void LogGetAndStop(const v8::FunctionCallbackInfo<v8::Value>& args);
static void TestVerifySourcePositions(
@@ -492,23 +525,34 @@ class Shell : public i::AllStatic {
static void Print(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PrintErr(const v8::FunctionCallbackInfo<v8::Value>& args);
- static void Write(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void WriteStdout(const v8::FunctionCallbackInfo<v8::Value>& args);
static void WaitUntilDone(const v8::FunctionCallbackInfo<v8::Value>& args);
static void NotifyDone(const v8::FunctionCallbackInfo<v8::Value>& args);
static void QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args);
static void Quit(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Version(const v8::FunctionCallbackInfo<v8::Value>& args);
- static void Read(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void ReadFile(const v8::FunctionCallbackInfo<v8::Value>& args);
static char* ReadChars(const char* name, int* size_out);
- static bool ReadLines(const char* name, std::vector<std::string>& lines);
+ static MaybeLocal<PrimitiveArray> ReadLines(Isolate* isolate,
+ const char* name);
static void ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args);
static Local<String> ReadFromStdin(Isolate* isolate);
static void ReadLine(const v8::FunctionCallbackInfo<v8::Value>& args) {
args.GetReturnValue().Set(ReadFromStdin(args.GetIsolate()));
}
static void WriteChars(const char* name, uint8_t* buffer, size_t buffer_size);
- static void Load(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void ExecuteFile(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetTimeout(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void ReadCodeTypeAndArguments(
+ const v8::FunctionCallbackInfo<v8::Value>& args, int index,
+ CodeType* code_type, Local<Value>* arguments = nullptr);
+ static bool FunctionAndArgumentsToString(Local<Function> function,
+ Local<Value> arguments,
+ Local<String>* source,
+ Isolate* isolate);
+ static MaybeLocal<String> ReadSource(
+ const v8::FunctionCallbackInfo<v8::Value>& args, int index,
+ CodeType default_type);
static void WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args);
static void WorkerPostMessage(
const v8::FunctionCallbackInfo<v8::Value>& args);
@@ -529,29 +573,30 @@ class Shell : public i::AllStatic {
// milliseconds on the total running time of the program. Exceptions are
// thrown on timeouts or other errors or if the exit status of the program
// indicates an error.
- //
+ static void System(const v8::FunctionCallbackInfo<v8::Value>& args);
+
// os.chdir(dir) changes directory to the given directory. Throws an
// exception/ on error.
- //
+ static void ChangeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
+
// os.setenv(variable, value) sets an environment variable. Repeated calls to
// this method leak memory due to the API of setenv in the standard C library.
- //
+ static void SetEnvironment(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void UnsetEnvironment(const v8::FunctionCallbackInfo<v8::Value>& args);
+
// os.umask(alue) calls the umask system call and returns the old umask.
- //
+ static void SetUMask(const v8::FunctionCallbackInfo<v8::Value>& args);
+
// os.mkdirp(name, mask) creates a directory. The mask (if present) is anded
// with the current umask. Intermediate directories are created if necessary.
// An exception is not thrown if the directory already exists. Analogous to
// the "mkdir -p" command.
- static void System(const v8::FunctionCallbackInfo<v8::Value>& args);
- static void ChangeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
- static void SetEnvironment(const v8::FunctionCallbackInfo<v8::Value>& args);
- static void UnsetEnvironment(const v8::FunctionCallbackInfo<v8::Value>& args);
- static void SetUMask(const v8::FunctionCallbackInfo<v8::Value>& args);
static void MakeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
static void RemoveDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
static MaybeLocal<Promise> HostImportModuleDynamically(
Local<Context> context, Local<ScriptOrModule> referrer,
Local<String> specifier, Local<FixedArray> import_assertions);
+
static void ModuleResolutionSuccessCallback(
const v8::FunctionCallbackInfo<v8::Value>& info);
static void ModuleResolutionFailureCallback(
@@ -601,6 +646,8 @@ class Shell : public i::AllStatic {
static void PromiseRejectCallback(v8::PromiseRejectMessage reject_message);
+ static Local<FunctionTemplate> CreateSnapshotTemplate(Isolate* isolate);
+
private:
static Global<Context> evaluation_context_;
static base::OnceType quit_once_;