v8/test/cctest/cctest.cc

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

431 lines
15 KiB
C++
Raw Normal View History

// 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"
Reland "[include] Split out v8.h" This is a reland of d1b27019d3bf86360ea838c317f8505fac6d3a7e Fixes include: Adding missing file to bazel build Forward-declaring classing before friend-classing them to fix win/gcc Add missing v8-isolate.h include for vtune builds Original change's description: > [include] Split out v8.h > > This moves every single class/function out of include/v8.h into a > separate header in include/, which v8.h then includes so that > externally nothing appears to have changed. > > Every include of v8.h from inside v8 has been changed to a more > fine-grained include. > > Previously inline functions defined at the bottom of v8.h would call > private non-inline functions in the V8 class. Since that class is now > in v8-initialization.h and is rarely included (as that would create > dependency cycles), this is not possible and so those methods have been > moved out of the V8 class into the namespace v8::api_internal. > > None of the previous files in include/ now #include v8.h, which means > if embedders were relying on this transitive dependency then it will > give compile failures. > > v8-inspector.h does depend on v8-scripts.h for the time being to ensure > that Chrome continue to compile but that change will be reverted once > those transitive #includes in chrome are changed to include it directly. > > Full design: > https://docs.google.com/document/d/1rTD--I8hCAr-Rho1WTumZzFKaDpEp0IJ8ejZtk4nJdA/edit?usp=sharing > > Bug: v8:11965 > Change-Id: I53b84b29581632710edc80eb11f819c2097a2877 > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3097448 > Reviewed-by: Yang Guo <yangguo@chromium.org> > Reviewed-by: Camillo Bruni <cbruni@chromium.org> > Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> > Reviewed-by: Leszek Swirski <leszeks@chromium.org> > Reviewed-by: Michael Lippautz <mlippautz@chromium.org> > Commit-Queue: Dan Elphick <delphick@chromium.org> > Cr-Commit-Position: refs/heads/main@{#76424} Cq-Include-Trybots: luci.v8.try:v8_linux_vtunejit Bug: v8:11965 Change-Id: I99f5d3a73bf8fe25b650adfaf9567dc4e44a09e6 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3113629 Reviewed-by: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Camillo Bruni <cbruni@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Simon Zünd <szuend@chromium.org> Commit-Queue: Dan Elphick <delphick@chromium.org> Cr-Commit-Position: refs/heads/main@{#76460}
2021-08-23 13:01:06 +00:00
#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/strings.h"
#include "src/codegen/compiler.h"
#include "src/codegen/optimized-compilation-info.h"
#include "src/compiler/pipeline.h"
#include "src/debug/debug.h"
#include "src/flags/flags.h"
#include "src/objects/objects-inl.h"
[wasm] Initial signal handler This is basically the minimum viable signal handler for Wasm bounds checks. It includes the TLS check and the fine grained instructions checks. These two checks provide most of the safety for the signal handler. Future CLs will add code range and data range checks for more robustness. The trap handling code and data structures are all in src/trap-handler, with the code that actually runs in the signal handler confined to src/trap-handler/signal-handler.cc. This changes adds a new V8 API that the embedder should call from a signal handler that will give V8 the chance to handle the fault first. For hosts that do not want to implement their own signal handler, we include the option to install a simple one. This simple handler is also used for the tests. When a Wasm module is instantiated, information about each function is passed to the trap handler, which is used to classify faults. These are removed during the instance finalizer. Several future enhancements are planned before turning this on by default. Obviously, the additional checks will be added to MaybeHandleFault. We are also planning to add a two-level CodeObjectData table that is grouped by isolates to make cleanup easier and also reduce potential for contending on a single data structure. BUG= https://bugs.chromium.org/p/v8/issues/detail?id=5277 Review-Url: https://codereview.chromium.org/2371833007 Cr-Original-Original-Commit-Position: refs/heads/master@{#43523} Committed: https://chromium.googlesource.com/v8/v8/+/a5af7fe9ee388a636675f4a6872b1d34fa7d1a7a Review-Url: https://codereview.chromium.org/2371833007 Cr-Original-Commit-Position: refs/heads/master@{#43755} Committed: https://chromium.googlesource.com/v8/v8/+/338622d7cae787a63cece1f2e79a8b030023940b Review-Url: https://codereview.chromium.org/2371833007 Cr-Commit-Position: refs/heads/master@{#43759}
2017-03-13 22:12:23 +00:00
#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 bool disable_automatic_dispose_ = false;
CcTest* CcTest::last_ = nullptr;
bool CcTest::initialize_called_ = false;
v8::base::Atomic32 CcTest::isolate_used_ = 0;
v8::ArrayBuffer::Allocator* CcTest::allocator_ = nullptr;
v8::Isolate* CcTest::isolate_ = nullptr;
CcTest::CcTest(TestFunction* callback, const char* file, const char* name,
bool enabled, bool initialize)
: callback_(callback),
name_(name),
enabled_(enabled),
initialize_(initialize),
prev_(last_) {
// 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
file_ = basename;
prev_ = last_;
last_ = this;
}
void CcTest::Run() {
if (!initialize_) {
CHECK_NE(initialization_state_, kInitialized);
initialization_state_ = kUninitialized;
CHECK_NULL(CcTest::isolate_);
} else {
CHECK_NE(initialization_state_, kUninitialized);
initialization_state_ = kInitialized;
if (isolate_ == nullptr) {
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 (v8::Locker::IsActive()) {
v8::Locker locker(isolate_);
EmptyMessageQueues(isolate_);
} else {
EmptyMessageQueues(isolate_);
}
isolate_->Exit();
}
}
i::Heap* CcTest::heap() { return i_isolate()->heap(); }
i::ReadOnlyHeap* CcTest::read_only_heap() {
return i_isolate()->read_only_heap();
}
[cpu-profiler] Ensure sampled thread has Isolate lock under Windows While the sampler checked if the sampled thread had the Isolate locked (if locks are being used) under Linux, the check was not done under Windows (or Fuchsia) which meant that in a multi-threading application under Windows, thread locking was not checked making it prone to seg faults and the like as the profiler would be using isolate->js_entry_sp to determine the stack to walk but isolate->js_entry_sp is the stack pointer for the thread that currently has the Isolate lock so, if the sampled thread does not have the lock, the sampler woud be iterating over the wrong stack, one that might actually be actively changing on another thread. The fix was to move the lock check into CpuSampler and Ticker (--prof) so all OSes would do the correct check. The basic concept is that on all operating systems a CpuProfiler, and so its corresponding CpuCampler, the profiler is tied to a thread. This is not based on first principles or anything, it's simply the way it works in V8, though it is a useful conceit as it makes visualization and interpretation of profile data much easier. To collect a sample on a thread associated with a profiler the thread must be stopped for obvious reasons -- walking the stack of a running thread is a formula for disaster. The mechanism for stopping a thread is OS-specific and is done in sample.cc. There are currently three basic approaches, one for Linux/Unix variants, one for Windows and one for Fuchsia. The approaches vary as to which thread actually collects the sample -- under Linux the sample is actually collected on the (interrupted) sampled thread whereas under Fuchsia/Windows it's on a separate thread. However, in a multi-threaded environment (where Locker is used), it's not sufficient for the sampled thread to be stopped. Because the stack walk involves looking in the Isolate heap, no other thread can be messing with the heap while the sample is collected. The only ways to ensure this would be to either stop all threads whenever collecting a sample, or to ensure that the thread being sampled holds the Isolate lock so prevents other threads from messing with the heap. While there might be something to be said for the "stop all threads" approach, the current approach in V8 is to only stop the sampled thread so, if in a multi-threaded environment, the profiler must check if the thread being sampled holds the Isolate lock. Since this check must be done, independent of which thread the sample is being collected on (since it varies from OS to OS), the approach is to save the thread id of the thread to be profiled/sampled when the CpuSampler is instantiated (on all OSes it is instantiated on the sampled thread) and then check that thread id against the Isolate lock holder thread id before collecting a sample. If it matches, we know sample.cc has stop the sampled thread, one way or another, and we know that no other thread can mess with the heap (since the stopped thread holds the Isolate lock) so it's safe to walk the stack and collect data from the heap so the sample can be taken. It it doesn't match, we can't safely collect the sample so we don't. Bug: v8:10850 Change-Id: Iba6cabcd3e11a19c261c004103e37e806934dc6f Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2411343 Reviewed-by: Peter Marshall <petermarshall@chromium.org> Commit-Queue: Peter Marshall <petermarshall@chromium.org> Cr-Commit-Position: refs/heads/master@{#69952}
2020-09-16 12:00:30 +00:00
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();
}
void CcTest::TearDown() {
if (isolate_ != nullptr) isolate_->Dispose();
}
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;
}
void CcTest::DisableAutomaticDispose() {
CHECK_EQ(kUninitialized, initialization_state_);
disable_automatic_dispose_ = true;
}
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(function, &is_compiled_scope);
i::Handle<i::Code> code =
i::compiler::Pipeline::GenerateCodeForTesting(&info, isolate, out_broker)
.ToHandleChecked();
info.native_context().AddOptimizedCode(*code);
function->set_code(*code, v8::kReleaseStore);
return function;
}
static void PrintTestList(CcTest* current) {
if (current == nullptr) return;
PrintTestList(current->prev());
printf("%s/%s\n", current->file(), current->name());
}
static void SuggestTestHarness(int tests) {
if (tests == 0) return;
printf("Running multiple tests in sequence is deprecated and may cause "
"bogus failure. Consider using tools/run-tests.py instead.\n");
}
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
v8::V8::InitializeICUDefaultLocation(argv[0]);
std::unique_ptr<v8::Platform> platform(v8::platform::NewDefaultPlatform());
v8::V8::InitializePlatform(platform.get());
#ifdef V8_VIRTUAL_MEMORY_CAGE
CHECK(v8::V8::InitializeVirtualMemoryCage());
#endif
cppgc::InitializeProcess(platform->GetPageAllocator());
using HelpOptions = v8::internal::FlagList::HelpOptions;
v8::internal::FlagList::SetFlagsFromCommandLine(
&argc, argv, true, HelpOptions(HelpOptions::kExit, usage.c_str()));
v8::V8::Initialize();
v8::V8::InitializeExternalStartupData(argv[0]);
#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
[wasm] Initial signal handler This is basically the minimum viable signal handler for Wasm bounds checks. It includes the TLS check and the fine grained instructions checks. These two checks provide most of the safety for the signal handler. Future CLs will add code range and data range checks for more robustness. The trap handling code and data structures are all in src/trap-handler, with the code that actually runs in the signal handler confined to src/trap-handler/signal-handler.cc. This changes adds a new V8 API that the embedder should call from a signal handler that will give V8 the chance to handle the fault first. For hosts that do not want to implement their own signal handler, we include the option to install a simple one. This simple handler is also used for the tests. When a Wasm module is instantiated, information about each function is passed to the trap handler, which is used to classify faults. These are removed during the instance finalizer. Several future enhancements are planned before turning this on by default. Obviously, the additional checks will be added to MaybeHandleFault. We are also planning to add a two-level CodeObjectData table that is grouped by isolates to make cleanup easier and also reduce potential for contending on a single data structure. BUG= https://bugs.chromium.org/p/v8/issues/detail?id=5277 Review-Url: https://codereview.chromium.org/2371833007 Cr-Original-Original-Commit-Position: refs/heads/master@{#43523} Committed: https://chromium.googlesource.com/v8/v8/+/a5af7fe9ee388a636675f4a6872b1d34fa7d1a7a Review-Url: https://codereview.chromium.org/2371833007 Cr-Original-Commit-Position: refs/heads/master@{#43755} Committed: https://chromium.googlesource.com/v8/v8/+/338622d7cae787a63cece1f2e79a8b030023940b Review-Url: https://codereview.chromium.org/2371833007 Cr-Commit-Position: refs/heads/master@{#43759}
2017-03-13 22:12:23 +00:00
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>());
int tests_run = 0;
bool print_run_count = true;
for (int i = 1; i < argc; i++) {
char* arg = argv[i];
if (strcmp(arg, "--list") == 0) {
PrintTestList(CcTest::last());
print_run_count = false;
} else {
char* arg_copy = v8::internal::StrDup(arg);
char* testname = strchr(arg_copy, '/');
if (testname) {
// Split the string in two by nulling the slash and then run
// exact matches.
*testname = 0;
char* file = arg_copy;
char* name = testname + 1;
CcTest* test = CcTest::last();
while (test != nullptr) {
if (test->enabled()
&& strcmp(test->file(), file) == 0
&& strcmp(test->name(), name) == 0) {
SuggestTestHarness(tests_run++);
test->Run();
}
test = test->prev();
}
} else {
// Run all tests with the specified file or test name.
char* file_or_name = arg_copy;
CcTest* test = CcTest::last();
while (test != nullptr) {
if (test->enabled()
&& (strcmp(test->file(), file_or_name) == 0
|| strcmp(test->name(), file_or_name) == 0)) {
SuggestTestHarness(tests_run++);
test->Run();
}
test = test->prev();
}
}
v8::internal::DeleteArray<char>(arg_copy);
}
}
if (print_run_count && tests_run != 1)
printf("Ran %i tests.\n", tests_run);
CcTest::TearDown();
if (!disable_automatic_dispose_) v8::V8::Dispose();
v8::V8::ShutdownPlatform();
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);
}