Line data Source code
1 : // Copyright 2017 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "testing/gtest/include/gtest/gtest.h"
6 :
7 : #include "include/libplatform/libplatform.h"
8 : #include "include/v8-platform.h"
9 : #include "include/v8.h"
10 : #include "src/base/macros.h"
11 : #include "src/base/platform/semaphore.h"
12 : #include "src/base/template-utils.h"
13 : #include "src/execution.h"
14 : #include "src/isolate.h"
15 : #include "src/v8.h"
16 : #include "test/unittests/test-utils.h"
17 :
18 : namespace v8 {
19 :
20 : typedef TestWithIsolate IsolateTest;
21 :
22 : namespace {
23 :
24 : class MemoryPressureTask : public v8::Task {
25 : public:
26 : MemoryPressureTask(Isolate* isolate, base::Semaphore* semaphore)
27 1 : : isolate_(isolate), semaphore_(semaphore) {}
28 2 : ~MemoryPressureTask() override = default;
29 :
30 : // v8::Task implementation.
31 1 : void Run() override {
32 1 : isolate_->MemoryPressureNotification(MemoryPressureLevel::kCritical);
33 1 : semaphore_->Signal();
34 1 : }
35 :
36 : private:
37 : Isolate* isolate_;
38 : base::Semaphore* semaphore_;
39 :
40 : DISALLOW_COPY_AND_ASSIGN(MemoryPressureTask);
41 : };
42 :
43 : } // namespace
44 :
45 : // Check that triggering a memory pressure notification on the isolate thread
46 : // doesn't request a GC interrupt.
47 15443 : TEST_F(IsolateTest, MemoryPressureNotificationForeground) {
48 : internal::Isolate* i_isolate =
49 : reinterpret_cast<internal::Isolate*>(isolate());
50 :
51 2 : ASSERT_FALSE(i_isolate->stack_guard()->CheckGC());
52 1 : isolate()->MemoryPressureNotification(MemoryPressureLevel::kCritical);
53 2 : ASSERT_FALSE(i_isolate->stack_guard()->CheckGC());
54 : }
55 :
56 : // Check that triggering a memory pressure notification on an background thread
57 : // requests a GC interrupt.
58 15443 : TEST_F(IsolateTest, MemoryPressureNotificationBackground) {
59 : internal::Isolate* i_isolate =
60 : reinterpret_cast<internal::Isolate*>(isolate());
61 :
62 2 : base::Semaphore semaphore(0);
63 :
64 2 : internal::V8::GetCurrentPlatform()->CallOnWorkerThread(
65 2 : base::make_unique<MemoryPressureTask>(isolate(), &semaphore));
66 :
67 1 : semaphore.Wait();
68 :
69 1 : ASSERT_TRUE(i_isolate->stack_guard()->CheckGC());
70 1 : v8::platform::PumpMessageLoop(internal::V8::GetCurrentPlatform(), isolate());
71 : }
72 :
73 : using IncumbentContextTest = TestWithIsolate;
74 :
75 : // Check that Isolate::GetIncumbentContext() returns the correct one in basic
76 : // scenarios.
77 15443 : TEST_F(IncumbentContextTest, Basic) {
78 13 : auto Str = [&](const char* s) {
79 13 : return String::NewFromUtf8(isolate(), s, NewStringType::kNormal)
80 : .ToLocalChecked();
81 14 : };
82 9 : auto Run = [&](Local<Context> context, const char* script) {
83 : Context::Scope scope(context);
84 9 : return Script::Compile(context, Str(script))
85 : .ToLocalChecked()
86 9 : ->Run(context)
87 9 : .ToLocalChecked();
88 : };
89 :
90 : // Set up the test environment; three contexts with getIncumbentGlobal()
91 : // function.
92 : Local<FunctionTemplate> get_incumbent_global = FunctionTemplate::New(
93 8 : isolate(), [](const FunctionCallbackInfo<Value>& info) {
94 : Local<Context> incumbent_context =
95 4 : info.GetIsolate()->GetIncumbentContext();
96 4 : info.GetReturnValue().Set(incumbent_context->Global());
97 9 : });
98 1 : Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate());
99 2 : global_template->Set(Str("getIncumbentGlobal"), get_incumbent_global);
100 :
101 1 : Local<Context> context_a = Context::New(isolate(), nullptr, global_template);
102 1 : Local<Context> context_b = Context::New(isolate(), nullptr, global_template);
103 1 : Local<Context> context_c = Context::New(isolate(), nullptr, global_template);
104 1 : Local<Object> global_a = context_a->Global();
105 1 : Local<Object> global_b = context_b->Global();
106 1 : Local<Object> global_c = context_c->Global();
107 :
108 1 : Local<String> security_token = Str("security_token");
109 1 : context_a->SetSecurityToken(security_token);
110 1 : context_b->SetSecurityToken(security_token);
111 1 : context_c->SetSecurityToken(security_token);
112 :
113 3 : global_a->Set(context_a, Str("b"), global_b).ToChecked();
114 3 : global_b->Set(context_b, Str("c"), global_c).ToChecked();
115 :
116 : // Test scenario 2: A -> B -> C, then the incumbent is C.
117 1 : Run(context_a, "funcA = function() { return b.funcB(); }");
118 1 : Run(context_b, "funcB = function() { return c.getIncumbentGlobal(); }");
119 : // Without BackupIncumbentScope.
120 2 : EXPECT_EQ(global_b, Run(context_a, "funcA()"));
121 : {
122 : // With BackupIncumbentScope.
123 2 : Context::BackupIncumbentScope backup_incumbent(context_a);
124 2 : EXPECT_EQ(global_b, Run(context_a, "funcA()"));
125 : }
126 :
127 : // Test scenario 2: A -> B -> C -> C, then the incumbent is C.
128 1 : Run(context_a, "funcA = function() { return b.funcB(); }");
129 1 : Run(context_b, "funcB = function() { return c.funcC(); }");
130 1 : Run(context_c, "funcC = function() { return getIncumbentGlobal(); }");
131 : // Without BackupIncumbentScope.
132 2 : EXPECT_EQ(global_c, Run(context_a, "funcA()"));
133 : {
134 : // With BackupIncumbentScope.
135 2 : Context::BackupIncumbentScope backup_incumbent(context_a);
136 2 : EXPECT_EQ(global_c, Run(context_a, "funcA()"));
137 : }
138 1 : }
139 :
140 9264 : } // namespace v8
|