46e95920e4
This CL explicitly disables the --freeze-flags-after-init flag for cases where we modify flags after initialization. This is only tests, fuzzers, and special options to d8, thus not security relevant. These should be the last blockers for enabling the flag globally. R=cbruni@chromium.org Bug: v8:12887 Change-Id: I1d8a03dcc20e524d30c967f6fe15f6401de77612 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3706619 Reviewed-by: Camillo Bruni <cbruni@chromium.org> Commit-Queue: Clemens Backes <clemensb@chromium.org> Cr-Commit-Position: refs/heads/main@{#81179}
561 lines
20 KiB
C++
561 lines
20 KiB
C++
// Copyright 2008 the V8 project authors. All rights reserved.
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following
|
|
// disclaimer in the documentation and/or other materials provided
|
|
// with the distribution.
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
// contributors may be used to endorse or promote products derived
|
|
// from this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
#include "test/cctest/cctest.h"
|
|
|
|
#include "include/cppgc/platform.h"
|
|
#include "include/libplatform/libplatform.h"
|
|
#include "include/v8-array-buffer.h"
|
|
#include "include/v8-context.h"
|
|
#include "include/v8-function.h"
|
|
#include "include/v8-isolate.h"
|
|
#include "include/v8-local-handle.h"
|
|
#include "include/v8-locker.h"
|
|
#include "src/base/lazy-instance.h"
|
|
#include "src/base/logging.h"
|
|
#include "src/base/platform/condition-variable.h"
|
|
#include "src/base/platform/mutex.h"
|
|
#include "src/base/platform/semaphore.h"
|
|
#include "src/base/strings.h"
|
|
#include "src/codegen/compiler.h"
|
|
#include "src/codegen/optimized-compilation-info.h"
|
|
#include "src/common/globals.h"
|
|
#include "src/compiler/pipeline.h"
|
|
#include "src/debug/debug.h"
|
|
#include "src/flags/flags.h"
|
|
#include "src/objects/objects-inl.h"
|
|
#include "src/trap-handler/trap-handler.h"
|
|
#include "test/cctest/print-extension.h"
|
|
#include "test/cctest/profiler-extension.h"
|
|
#include "test/cctest/trace-extension.h"
|
|
|
|
#ifdef V8_USE_PERFETTO
|
|
#include "src/tracing/trace-event.h"
|
|
#endif // V8_USE_PERFETTO
|
|
|
|
#if V8_OS_WIN
|
|
#include <windows.h>
|
|
#if V8_CC_MSVC
|
|
#include <crtdbg.h>
|
|
#endif
|
|
#endif
|
|
|
|
enum InitializationState { kUnset, kUninitialized, kInitialized };
|
|
static InitializationState initialization_state_ = kUnset;
|
|
|
|
static v8::base::LazyInstance<CcTestMapType>::type g_cctests =
|
|
LAZY_INSTANCE_INITIALIZER;
|
|
|
|
std::unordered_map<std::string, CcTest*>* tests_ =
|
|
new std::unordered_map<std::string, CcTest*>();
|
|
bool CcTest::initialize_called_ = false;
|
|
v8::base::Atomic32 CcTest::isolate_used_ = 0;
|
|
v8::ArrayBuffer::Allocator* CcTest::allocator_ = nullptr;
|
|
v8::Isolate* CcTest::isolate_ = nullptr;
|
|
v8::Platform* CcTest::default_platform_ = nullptr;
|
|
|
|
CcTest::CcTest(TestFunction* callback, const char* file, const char* name,
|
|
bool enabled, bool initialize,
|
|
TestPlatformFactory* test_platform_factory)
|
|
: callback_(callback),
|
|
initialize_(initialize),
|
|
test_platform_factory_(test_platform_factory) {
|
|
// Find the base name of this test (const_cast required on Windows).
|
|
char *basename = strrchr(const_cast<char *>(file), '/');
|
|
if (!basename) {
|
|
basename = strrchr(const_cast<char *>(file), '\\');
|
|
}
|
|
if (!basename) {
|
|
basename = v8::internal::StrDup(file);
|
|
} else {
|
|
basename = v8::internal::StrDup(basename + 1);
|
|
}
|
|
// Drop the extension, if there is one.
|
|
char *extension = strrchr(basename, '.');
|
|
if (extension) *extension = 0;
|
|
// Install this test in the list of tests
|
|
|
|
if (enabled) {
|
|
auto it =
|
|
g_cctests.Pointer()->emplace(std::string(basename) + "/" + name, this);
|
|
CHECK_WITH_MSG(it.second, "Test with same name already exists");
|
|
}
|
|
v8::internal::DeleteArray(basename);
|
|
}
|
|
|
|
void CcTest::Run(const char* snapshot_directory) {
|
|
v8::V8::InitializeICUDefaultLocation(snapshot_directory);
|
|
std::unique_ptr<v8::Platform> underlying_default_platform(
|
|
v8::platform::NewDefaultPlatform());
|
|
default_platform_ = underlying_default_platform.get();
|
|
std::unique_ptr<v8::Platform> platform;
|
|
if (test_platform_factory_) {
|
|
platform = test_platform_factory_();
|
|
} else {
|
|
platform = std::move(underlying_default_platform);
|
|
}
|
|
v8::V8::InitializePlatform(platform.get());
|
|
#ifdef V8_ENABLE_SANDBOX
|
|
CHECK(v8::V8::InitializeSandbox());
|
|
#endif
|
|
cppgc::InitializeProcess(platform->GetPageAllocator());
|
|
|
|
// Allow changing flags in cctests.
|
|
// TODO(12887): Fix tests to avoid changing flag values after initialization.
|
|
i::FLAG_freeze_flags_after_init = false;
|
|
|
|
v8::V8::Initialize();
|
|
v8::V8::InitializeExternalStartupData(snapshot_directory);
|
|
|
|
#if V8_ENABLE_WEBASSEMBLY && V8_TRAP_HANDLER_SUPPORTED
|
|
constexpr bool kUseDefaultTrapHandler = true;
|
|
CHECK(v8::V8::EnableWebAssemblyTrapHandler(kUseDefaultTrapHandler));
|
|
#endif // V8_ENABLE_WEBASSEMBLY && V8_TRAP_HANDLER_SUPPORTED
|
|
|
|
CcTest::set_array_buffer_allocator(
|
|
v8::ArrayBuffer::Allocator::NewDefaultAllocator());
|
|
|
|
v8::RegisterExtension(std::make_unique<i::PrintExtension>());
|
|
v8::RegisterExtension(std::make_unique<i::ProfilerExtension>());
|
|
v8::RegisterExtension(std::make_unique<i::TraceExtension>());
|
|
|
|
if (!initialize_) {
|
|
CHECK_NE(initialization_state_, kInitialized);
|
|
initialization_state_ = kUninitialized;
|
|
CHECK_NULL(isolate_);
|
|
} else {
|
|
CHECK_NE(initialization_state_, kUninitialized);
|
|
initialization_state_ = kInitialized;
|
|
CHECK_NULL(isolate_);
|
|
v8::Isolate::CreateParams create_params;
|
|
create_params.array_buffer_allocator = allocator_;
|
|
isolate_ = v8::Isolate::New(create_params);
|
|
isolate_->Enter();
|
|
}
|
|
#ifdef DEBUG
|
|
const size_t active_isolates = i::Isolate::non_disposed_isolates();
|
|
#endif // DEBUG
|
|
callback_();
|
|
#ifdef DEBUG
|
|
// This DCHECK ensures that all Isolates are properly disposed after finishing
|
|
// the test. Stray Isolates lead to stray tasks in the platform which can
|
|
// interact weirdly when swapping in new platforms (for testing) or during
|
|
// shutdown.
|
|
DCHECK_EQ(active_isolates, i::Isolate::non_disposed_isolates());
|
|
#endif // DEBUG
|
|
if (initialize_) {
|
|
if (i_isolate()->was_locker_ever_used()) {
|
|
v8::Locker locker(isolate_);
|
|
EmptyMessageQueues(isolate_);
|
|
} else {
|
|
EmptyMessageQueues(isolate_);
|
|
}
|
|
isolate_->Exit();
|
|
isolate_->Dispose();
|
|
isolate_ = nullptr;
|
|
} else {
|
|
CHECK_NULL(isolate_);
|
|
}
|
|
|
|
v8::V8::Dispose();
|
|
cppgc::ShutdownProcess();
|
|
v8::V8::DisposePlatform();
|
|
}
|
|
|
|
i::Heap* CcTest::heap() { return i_isolate()->heap(); }
|
|
i::ReadOnlyHeap* CcTest::read_only_heap() {
|
|
return i_isolate()->read_only_heap();
|
|
}
|
|
|
|
void CcTest::AddGlobalFunction(v8::Local<v8::Context> env, const char* name,
|
|
v8::FunctionCallback callback) {
|
|
v8::Local<v8::FunctionTemplate> func_template =
|
|
v8::FunctionTemplate::New(isolate_, callback);
|
|
v8::Local<v8::Function> func =
|
|
func_template->GetFunction(env).ToLocalChecked();
|
|
func->SetName(v8_str(name));
|
|
env->Global()->Set(env, v8_str(name), func).FromJust();
|
|
}
|
|
|
|
void CcTest::CollectGarbage(i::AllocationSpace space, i::Isolate* isolate) {
|
|
i::Isolate* iso = isolate ? isolate : i_isolate();
|
|
iso->heap()->CollectGarbage(space, i::GarbageCollectionReason::kTesting);
|
|
}
|
|
|
|
void CcTest::CollectAllGarbage(i::Isolate* isolate) {
|
|
i::Isolate* iso = isolate ? isolate : i_isolate();
|
|
iso->heap()->CollectAllGarbage(i::Heap::kNoGCFlags,
|
|
i::GarbageCollectionReason::kTesting);
|
|
}
|
|
|
|
void CcTest::CollectAllAvailableGarbage(i::Isolate* isolate) {
|
|
i::Isolate* iso = isolate ? isolate : i_isolate();
|
|
iso->heap()->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
|
|
}
|
|
|
|
void CcTest::PreciseCollectAllGarbage(i::Isolate* isolate) {
|
|
i::Isolate* iso = isolate ? isolate : i_isolate();
|
|
iso->heap()->PreciseCollectAllGarbage(i::Heap::kNoGCFlags,
|
|
i::GarbageCollectionReason::kTesting);
|
|
}
|
|
|
|
i::Handle<i::String> CcTest::MakeString(const char* str) {
|
|
i::Isolate* isolate = CcTest::i_isolate();
|
|
i::Factory* factory = isolate->factory();
|
|
return factory->InternalizeUtf8String(str);
|
|
}
|
|
|
|
i::Handle<i::String> CcTest::MakeName(const char* str, int suffix) {
|
|
v8::base::EmbeddedVector<char, 128> buffer;
|
|
v8::base::SNPrintF(buffer, "%s%d", str, suffix);
|
|
return CcTest::MakeString(buffer.begin());
|
|
}
|
|
|
|
v8::base::RandomNumberGenerator* CcTest::random_number_generator() {
|
|
return InitIsolateOnce()->random_number_generator();
|
|
}
|
|
|
|
v8::Local<v8::Object> CcTest::global() {
|
|
return isolate()->GetCurrentContext()->Global();
|
|
}
|
|
|
|
void CcTest::InitializeVM() {
|
|
CHECK(!v8::base::Relaxed_Load(&isolate_used_));
|
|
CHECK(!initialize_called_);
|
|
initialize_called_ = true;
|
|
v8::HandleScope handle_scope(CcTest::isolate());
|
|
v8::Context::New(CcTest::isolate())->Enter();
|
|
}
|
|
|
|
v8::Local<v8::Context> CcTest::NewContext(CcTestExtensionFlags extension_flags,
|
|
v8::Isolate* isolate) {
|
|
const char* extension_names[kMaxExtensions];
|
|
int extension_count = 0;
|
|
for (int i = 0; i < kMaxExtensions; ++i) {
|
|
if (!extension_flags.contains(static_cast<CcTestExtensionId>(i))) continue;
|
|
extension_names[extension_count] = kExtensionName[i];
|
|
++extension_count;
|
|
}
|
|
v8::ExtensionConfiguration config(extension_count, extension_names);
|
|
v8::Local<v8::Context> context = v8::Context::New(isolate, &config);
|
|
CHECK(!context.IsEmpty());
|
|
return context;
|
|
}
|
|
|
|
LocalContext::~LocalContext() {
|
|
v8::HandleScope scope(isolate_);
|
|
v8::Local<v8::Context>::New(isolate_, context_)->Exit();
|
|
context_.Reset();
|
|
}
|
|
|
|
void LocalContext::Initialize(v8::Isolate* isolate,
|
|
v8::ExtensionConfiguration* extensions,
|
|
v8::Local<v8::ObjectTemplate> global_template,
|
|
v8::Local<v8::Value> global_object) {
|
|
v8::HandleScope scope(isolate);
|
|
v8::Local<v8::Context> context =
|
|
v8::Context::New(isolate, extensions, global_template, global_object);
|
|
context_.Reset(isolate, context);
|
|
context->Enter();
|
|
// We can't do this later perhaps because of a fatal error.
|
|
isolate_ = isolate;
|
|
}
|
|
|
|
// This indirection is needed because HandleScopes cannot be heap-allocated, and
|
|
// we don't want any unnecessary #includes in cctest.h.
|
|
class V8_NODISCARD InitializedHandleScopeImpl {
|
|
public:
|
|
explicit InitializedHandleScopeImpl(i::Isolate* isolate)
|
|
: handle_scope_(isolate) {}
|
|
|
|
private:
|
|
i::HandleScope handle_scope_;
|
|
};
|
|
|
|
InitializedHandleScope::InitializedHandleScope(i::Isolate* isolate)
|
|
: main_isolate_(isolate ? isolate : CcTest::InitIsolateOnce()),
|
|
initialized_handle_scope_impl_(
|
|
new InitializedHandleScopeImpl(main_isolate_)) {}
|
|
|
|
InitializedHandleScope::~InitializedHandleScope() = default;
|
|
|
|
HandleAndZoneScope::HandleAndZoneScope(bool support_zone_compression)
|
|
: main_zone_(
|
|
new i::Zone(&allocator_, ZONE_NAME, support_zone_compression)) {}
|
|
|
|
HandleAndZoneScope::~HandleAndZoneScope() = default;
|
|
|
|
i::Handle<i::JSFunction> Optimize(
|
|
i::Handle<i::JSFunction> function, i::Zone* zone, i::Isolate* isolate,
|
|
uint32_t flags, std::unique_ptr<i::compiler::JSHeapBroker>* out_broker) {
|
|
i::Handle<i::SharedFunctionInfo> shared(function->shared(), isolate);
|
|
i::IsCompiledScope is_compiled_scope(shared->is_compiled_scope(isolate));
|
|
CHECK(is_compiled_scope.is_compiled() ||
|
|
i::Compiler::Compile(isolate, function, i::Compiler::CLEAR_EXCEPTION,
|
|
&is_compiled_scope));
|
|
|
|
CHECK_NOT_NULL(zone);
|
|
|
|
i::OptimizedCompilationInfo info(zone, isolate, shared, function,
|
|
i::CodeKind::TURBOFAN);
|
|
|
|
if (flags & ~i::OptimizedCompilationInfo::kInlining) UNIMPLEMENTED();
|
|
if (flags & i::OptimizedCompilationInfo::kInlining) {
|
|
info.set_inlining();
|
|
}
|
|
|
|
CHECK(info.shared_info()->HasBytecodeArray());
|
|
i::JSFunction::EnsureFeedbackVector(isolate, function, &is_compiled_scope);
|
|
|
|
i::Handle<i::CodeT> code = i::ToCodeT(
|
|
i::compiler::Pipeline::GenerateCodeForTesting(&info, isolate, out_broker)
|
|
.ToHandleChecked(),
|
|
isolate);
|
|
info.native_context().AddOptimizedCode(*code);
|
|
function->set_code(*code, v8::kReleaseStore);
|
|
return function;
|
|
}
|
|
|
|
static void PrintTestList() {
|
|
int test_num = 0;
|
|
for (const auto& entry : g_cctests.Get()) {
|
|
printf("**>Test: %s\n", entry.first.c_str());
|
|
test_num++;
|
|
}
|
|
printf("\nTotal number of tests: %d\n", test_num);
|
|
}
|
|
|
|
int main(int argc, char* argv[]) {
|
|
#if V8_OS_WIN
|
|
UINT new_flags =
|
|
SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
|
|
UINT existing_flags = SetErrorMode(new_flags);
|
|
SetErrorMode(existing_flags | new_flags);
|
|
#if V8_CC_MSVC
|
|
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
|
|
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
|
|
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
|
|
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
|
|
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
|
|
_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
|
|
_set_error_mode(_OUT_TO_STDERR);
|
|
#endif // V8_CC_MSVC
|
|
#endif // V8_OS_WIN
|
|
|
|
std::string usage = "Usage: " + std::string(argv[0]) + " [--list]" +
|
|
" [[V8_FLAGS] CCTEST]\n\n" + "Options:\n" +
|
|
" --list: list all cctests\n" +
|
|
" CCTEST: cctest identfier returned by --list\n" +
|
|
" V8_FLAGS: see V8 options below\n\n\n";
|
|
|
|
#ifdef V8_USE_PERFETTO
|
|
// Set up the in-process backend that the tracing controller will connect to.
|
|
perfetto::TracingInitArgs init_args;
|
|
init_args.backends = perfetto::BackendType::kInProcessBackend;
|
|
perfetto::Tracing::Initialize(init_args);
|
|
#endif // V8_USE_PERFETTO
|
|
|
|
using HelpOptions = v8::internal::FlagList::HelpOptions;
|
|
v8::internal::FlagList::SetFlagsFromCommandLine(
|
|
&argc, argv, true, HelpOptions(HelpOptions::kExit, usage.c_str()));
|
|
|
|
const char* test_arg = nullptr;
|
|
for (int i = 1; i < argc; ++i) {
|
|
const char* arg = argv[i];
|
|
if (strcmp(arg, "--list") == 0) {
|
|
PrintTestList();
|
|
return 0;
|
|
}
|
|
if (*arg == '-') {
|
|
// Ignore flags that weren't removed by SetFlagsFromCommandLine
|
|
continue;
|
|
}
|
|
if (test_arg != nullptr) {
|
|
fprintf(stderr,
|
|
"Running multiple tests in sequence is not allowed. Use "
|
|
"tools/run-tests.py instead.\n");
|
|
return 1;
|
|
}
|
|
test_arg = arg;
|
|
}
|
|
|
|
if (test_arg == nullptr) {
|
|
printf("Ran 0 tests.\n");
|
|
return 0;
|
|
}
|
|
|
|
auto it = g_cctests.Get().find(test_arg);
|
|
if (it == g_cctests.Get().end()) {
|
|
fprintf(stderr, "ERROR: Did not find test %s.\n", test_arg);
|
|
return 1;
|
|
}
|
|
|
|
CcTest* test = it->second;
|
|
test->Run(argv[0]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
RegisterThreadedTest* RegisterThreadedTest::first_ = nullptr;
|
|
int RegisterThreadedTest::count_ = 0;
|
|
|
|
bool IsValidUnwrapObject(v8::Object* object) {
|
|
i::Address addr = *reinterpret_cast<i::Address*>(object);
|
|
auto instance_type = i::Internals::GetInstanceType(addr);
|
|
return (v8::base::IsInRange(instance_type,
|
|
i::Internals::kFirstJSApiObjectType,
|
|
i::Internals::kLastJSApiObjectType) ||
|
|
instance_type == i::Internals::kJSObjectType ||
|
|
instance_type == i::Internals::kJSSpecialApiObjectType);
|
|
}
|
|
|
|
ManualGCScope::ManualGCScope(i::Isolate* isolate)
|
|
: flag_concurrent_marking_(i::FLAG_concurrent_marking),
|
|
flag_concurrent_sweeping_(i::FLAG_concurrent_sweeping),
|
|
flag_stress_concurrent_allocation_(i::FLAG_stress_concurrent_allocation),
|
|
flag_stress_incremental_marking_(i::FLAG_stress_incremental_marking),
|
|
flag_parallel_marking_(i::FLAG_parallel_marking),
|
|
flag_detect_ineffective_gcs_near_heap_limit_(
|
|
i::FLAG_detect_ineffective_gcs_near_heap_limit) {
|
|
// Some tests run threaded (back-to-back) and thus the GC may already be
|
|
// running by the time a ManualGCScope is created. Finalizing existing marking
|
|
// prevents any undefined/unexpected behavior.
|
|
if (isolate && isolate->heap()->incremental_marking()->IsMarking()) {
|
|
CcTest::CollectGarbage(i::OLD_SPACE, isolate);
|
|
}
|
|
|
|
i::FLAG_concurrent_marking = false;
|
|
i::FLAG_concurrent_sweeping = false;
|
|
i::FLAG_stress_incremental_marking = false;
|
|
i::FLAG_stress_concurrent_allocation = false;
|
|
// Parallel marking has a dependency on concurrent marking.
|
|
i::FLAG_parallel_marking = false;
|
|
i::FLAG_detect_ineffective_gcs_near_heap_limit = false;
|
|
}
|
|
|
|
ManualGCScope::~ManualGCScope() {
|
|
i::FLAG_concurrent_marking = flag_concurrent_marking_;
|
|
i::FLAG_concurrent_sweeping = flag_concurrent_sweeping_;
|
|
i::FLAG_stress_concurrent_allocation = flag_stress_concurrent_allocation_;
|
|
i::FLAG_stress_incremental_marking = flag_stress_incremental_marking_;
|
|
i::FLAG_parallel_marking = flag_parallel_marking_;
|
|
i::FLAG_detect_ineffective_gcs_near_heap_limit =
|
|
flag_detect_ineffective_gcs_near_heap_limit_;
|
|
}
|
|
|
|
v8::PageAllocator* TestPlatform::GetPageAllocator() {
|
|
return CcTest::default_platform()->GetPageAllocator();
|
|
}
|
|
|
|
void TestPlatform::OnCriticalMemoryPressure() {
|
|
CcTest::default_platform()->OnCriticalMemoryPressure();
|
|
}
|
|
|
|
bool TestPlatform::OnCriticalMemoryPressure(size_t length) {
|
|
return CcTest::default_platform()->OnCriticalMemoryPressure(length);
|
|
}
|
|
|
|
int TestPlatform::NumberOfWorkerThreads() {
|
|
return CcTest::default_platform()->NumberOfWorkerThreads();
|
|
}
|
|
|
|
std::shared_ptr<v8::TaskRunner> TestPlatform::GetForegroundTaskRunner(
|
|
v8::Isolate* isolate) {
|
|
return CcTest::default_platform()->GetForegroundTaskRunner(isolate);
|
|
}
|
|
|
|
void TestPlatform::CallOnWorkerThread(std::unique_ptr<v8::Task> task) {
|
|
CcTest::default_platform()->CallOnWorkerThread(std::move(task));
|
|
}
|
|
|
|
void TestPlatform::CallDelayedOnWorkerThread(std::unique_ptr<v8::Task> task,
|
|
double delay_in_seconds) {
|
|
CcTest::default_platform()->CallDelayedOnWorkerThread(std::move(task),
|
|
delay_in_seconds);
|
|
}
|
|
|
|
std::unique_ptr<v8::JobHandle> TestPlatform::PostJob(
|
|
v8::TaskPriority priority, std::unique_ptr<v8::JobTask> job_task) {
|
|
return CcTest::default_platform()->PostJob(priority, std::move(job_task));
|
|
}
|
|
|
|
std::unique_ptr<v8::JobHandle> TestPlatform::CreateJob(
|
|
v8::TaskPriority priority, std::unique_ptr<v8::JobTask> job_task) {
|
|
return CcTest::default_platform()->CreateJob(priority, std::move(job_task));
|
|
}
|
|
|
|
double TestPlatform::MonotonicallyIncreasingTime() {
|
|
return CcTest::default_platform()->MonotonicallyIncreasingTime();
|
|
}
|
|
|
|
double TestPlatform::CurrentClockTimeMillis() {
|
|
return CcTest::default_platform()->CurrentClockTimeMillis();
|
|
}
|
|
|
|
bool TestPlatform::IdleTasksEnabled(v8::Isolate* isolate) {
|
|
return CcTest::default_platform()->IdleTasksEnabled(isolate);
|
|
}
|
|
|
|
v8::TracingController* TestPlatform::GetTracingController() {
|
|
return CcTest::default_platform()->GetTracingController();
|
|
}
|
|
|
|
namespace {
|
|
|
|
class ShutdownTask final : public v8::Task {
|
|
public:
|
|
ShutdownTask(v8::base::Semaphore* destruction_barrier,
|
|
v8::base::Mutex* destruction_mutex,
|
|
v8::base::ConditionVariable* destruction_condition,
|
|
bool* can_destruct)
|
|
: destruction_barrier_(destruction_barrier),
|
|
destruction_mutex_(destruction_mutex),
|
|
destruction_condition_(destruction_condition),
|
|
can_destruct_(can_destruct)
|
|
|
|
{}
|
|
|
|
void Run() final {
|
|
destruction_barrier_->Signal();
|
|
{
|
|
v8::base::MutexGuard guard(destruction_mutex_);
|
|
while (!*can_destruct_) {
|
|
destruction_condition_->Wait(destruction_mutex_);
|
|
}
|
|
}
|
|
destruction_barrier_->Signal();
|
|
}
|
|
|
|
private:
|
|
v8::base::Semaphore* const destruction_barrier_;
|
|
v8::base::Mutex* const destruction_mutex_;
|
|
v8::base::ConditionVariable* const destruction_condition_;
|
|
bool* const can_destruct_;
|
|
};
|
|
|
|
} // namespace
|