v8/test/unittests/api/isolate-unittest.cc
Dan Elphick b097a8e5de [api] Create v8::String::NewFromLiteral that returns Local<String>
String::NewFromLiteral is a templated function that takes a char[N]
argument that can be used as an alternative to String::NewFromUtf8 and
returns a Local<String> rather than a MaybeLocal<String> reducing the
number of ToLocalChecked() or other checks.

Since the string length is known at compile time, it can statically
assert that the length is less than String::kMaxLength, which means that
it can never fail at runtime.

This also converts all found uses of NewFromUtf8 taking a string literal
or a variable initialized from a string literal to use the new API. In
some cases the types of stored string literals are changed from const
char* to const char[] to ensure the size is retained.

This API does introduce a small difference compared to NewFromUtf8. For
a case like "abc\0def", NewFromUtf8 (using length -1 to infer length)
would treat this as a 3 character string, whereas the new API will treat
it as a 7 character string.

As a drive-by fix, this also fixes all redundant uses of
v8::NewStringType::kNormal when passed to any of the String::New*
functions.

Change-Id: Id96a44bc068d9c4eaa634aea688e024675a0e5b3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2089935
Commit-Queue: Dan Elphick <delphick@chromium.org>
Reviewed-by: Mathias Bynens <mathias@chromium.org>
Reviewed-by: Mythri Alle <mythria@chromium.org>
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66622}
2020-03-09 12:02:07 +00:00

139 lines
4.7 KiB
C++

// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "testing/gtest/include/gtest/gtest.h"
#include "include/libplatform/libplatform.h"
#include "include/v8-platform.h"
#include "include/v8.h"
#include "src/base/macros.h"
#include "src/base/platform/semaphore.h"
#include "src/execution/execution.h"
#include "src/execution/isolate.h"
#include "src/init/v8.h"
#include "test/unittests/test-utils.h"
namespace v8 {
using IsolateTest = TestWithIsolate;
namespace {
class MemoryPressureTask : public v8::Task {
public:
MemoryPressureTask(Isolate* isolate, base::Semaphore* semaphore)
: isolate_(isolate), semaphore_(semaphore) {}
~MemoryPressureTask() override = default;
// v8::Task implementation.
void Run() override {
isolate_->MemoryPressureNotification(MemoryPressureLevel::kCritical);
semaphore_->Signal();
}
private:
Isolate* isolate_;
base::Semaphore* semaphore_;
DISALLOW_COPY_AND_ASSIGN(MemoryPressureTask);
};
} // namespace
// Check that triggering a memory pressure notification on the isolate thread
// doesn't request a GC interrupt.
TEST_F(IsolateTest, MemoryPressureNotificationForeground) {
internal::Isolate* i_isolate =
reinterpret_cast<internal::Isolate*>(isolate());
ASSERT_FALSE(i_isolate->stack_guard()->CheckGC());
isolate()->MemoryPressureNotification(MemoryPressureLevel::kCritical);
ASSERT_FALSE(i_isolate->stack_guard()->CheckGC());
}
// Check that triggering a memory pressure notification on an background thread
// requests a GC interrupt.
TEST_F(IsolateTest, MemoryPressureNotificationBackground) {
internal::Isolate* i_isolate =
reinterpret_cast<internal::Isolate*>(isolate());
base::Semaphore semaphore(0);
internal::V8::GetCurrentPlatform()->CallOnWorkerThread(
std::make_unique<MemoryPressureTask>(isolate(), &semaphore));
semaphore.Wait();
ASSERT_TRUE(i_isolate->stack_guard()->CheckGC());
v8::platform::PumpMessageLoop(internal::V8::GetCurrentPlatform(), isolate());
}
using IncumbentContextTest = TestWithIsolate;
// Check that Isolate::GetIncumbentContext() returns the correct one in basic
// scenarios.
TEST_F(IncumbentContextTest, Basic) {
auto Str = [&](const char* s) {
return String::NewFromUtf8(isolate(), s).ToLocalChecked();
};
auto Run = [&](Local<Context> context, const char* script) {
Context::Scope scope(context);
return Script::Compile(context, Str(script))
.ToLocalChecked()
->Run(context)
.ToLocalChecked();
};
// Set up the test environment; three contexts with getIncumbentGlobal()
// function.
Local<FunctionTemplate> get_incumbent_global = FunctionTemplate::New(
isolate(), [](const FunctionCallbackInfo<Value>& info) {
Local<Context> incumbent_context =
info.GetIsolate()->GetIncumbentContext();
info.GetReturnValue().Set(incumbent_context->Global());
});
Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate());
global_template->Set(Str("getIncumbentGlobal"), get_incumbent_global);
Local<Context> context_a = Context::New(isolate(), nullptr, global_template);
Local<Context> context_b = Context::New(isolate(), nullptr, global_template);
Local<Context> context_c = Context::New(isolate(), nullptr, global_template);
Local<Object> global_a = context_a->Global();
Local<Object> global_b = context_b->Global();
Local<Object> global_c = context_c->Global();
Local<String> security_token = Str("security_token");
context_a->SetSecurityToken(security_token);
context_b->SetSecurityToken(security_token);
context_c->SetSecurityToken(security_token);
global_a->Set(context_a, Str("b"), global_b).ToChecked();
global_b->Set(context_b, Str("c"), global_c).ToChecked();
// Test scenario 2: A -> B -> C, then the incumbent is C.
Run(context_a, "funcA = function() { return b.funcB(); }");
Run(context_b, "funcB = function() { return c.getIncumbentGlobal(); }");
// Without BackupIncumbentScope.
EXPECT_EQ(global_b, Run(context_a, "funcA()"));
{
// With BackupIncumbentScope.
Context::BackupIncumbentScope backup_incumbent(context_a);
EXPECT_EQ(global_b, Run(context_a, "funcA()"));
}
// Test scenario 2: A -> B -> C -> C, then the incumbent is C.
Run(context_a, "funcA = function() { return b.funcB(); }");
Run(context_b, "funcB = function() { return c.funcC(); }");
Run(context_c, "funcC = function() { return getIncumbentGlobal(); }");
// Without BackupIncumbentScope.
EXPECT_EQ(global_c, Run(context_a, "funcA()"));
{
// With BackupIncumbentScope.
Context::BackupIncumbentScope backup_incumbent(context_a);
EXPECT_EQ(global_c, Run(context_a, "funcA()"));
}
}
} // namespace v8