The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / test / cctest / test-thread-termination.cc @ f230a1cf

History | View | Annotate | Download (13.6 KB)

1
// Copyright 2009 the V8 project authors. All rights reserved.
2
// Redistribution and use in source and binary forms, with or without
3
// modification, are permitted provided that the following conditions are
4
// met:
5
//
6
//     * Redistributions of source code must retain the above copyright
7
//       notice, this list of conditions and the following disclaimer.
8
//     * Redistributions in binary form must reproduce the above
9
//       copyright notice, this list of conditions and the following
10
//       disclaimer in the documentation and/or other materials provided
11
//       with the distribution.
12
//     * Neither the name of Google Inc. nor the names of its
13
//       contributors may be used to endorse or promote products derived
14
//       from this software without specific prior written permission.
15
//
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27

    
28
#include "v8.h"
29
#include "platform.h"
30
#include "cctest.h"
31

    
32

    
33
v8::internal::Semaphore* semaphore = NULL;
34

    
35

    
36
void Signal(const v8::FunctionCallbackInfo<v8::Value>& args) {
37
  semaphore->Signal();
38
}
39

    
40

    
41
void TerminateCurrentThread(const v8::FunctionCallbackInfo<v8::Value>& args) {
42
  CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate()));
43
  v8::V8::TerminateExecution(args.GetIsolate());
44
}
45

    
46

    
47
void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
48
  CHECK(false);
49
}
50

    
51

    
52
void Loop(const v8::FunctionCallbackInfo<v8::Value>& args) {
53
  CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate()));
54
  v8::Handle<v8::String> source =
55
      v8::String::New("try { doloop(); fail(); } catch(e) { fail(); }");
56
  v8::Handle<v8::Value> result = v8::Script::Compile(source)->Run();
57
  CHECK(result.IsEmpty());
58
  CHECK(v8::V8::IsExecutionTerminating(args.GetIsolate()));
59
}
60

    
61

    
62
void DoLoop(const v8::FunctionCallbackInfo<v8::Value>& args) {
63
  v8::TryCatch try_catch;
64
  CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate()));
65
  v8::Script::Compile(v8::String::New("function f() {"
66
                                      "  var term = true;"
67
                                      "  try {"
68
                                      "    while(true) {"
69
                                      "      if (term) terminate();"
70
                                      "      term = false;"
71
                                      "    }"
72
                                      "    fail();"
73
                                      "  } catch(e) {"
74
                                      "    fail();"
75
                                      "  }"
76
                                      "}"
77
                                      "f()"))->Run();
78
  CHECK(try_catch.HasCaught());
79
  CHECK(try_catch.Exception()->IsNull());
80
  CHECK(try_catch.Message().IsEmpty());
81
  CHECK(!try_catch.CanContinue());
82
  CHECK(v8::V8::IsExecutionTerminating(args.GetIsolate()));
83
}
84

    
85

    
86
void DoLoopNoCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
87
  v8::TryCatch try_catch;
88
  CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate()));
89
  v8::Script::Compile(v8::String::New("var term = true;"
90
                                      "while(true) {"
91
                                      "  if (term) terminate();"
92
                                      "  term = false;"
93
                                      "}"))->Run();
94
  CHECK(try_catch.HasCaught());
95
  CHECK(try_catch.Exception()->IsNull());
96
  CHECK(try_catch.Message().IsEmpty());
97
  CHECK(!try_catch.CanContinue());
98
  CHECK(v8::V8::IsExecutionTerminating(args.GetIsolate()));
99
}
100

    
101

    
102
v8::Handle<v8::ObjectTemplate> CreateGlobalTemplate(
103
    v8::FunctionCallback terminate,
104
    v8::FunctionCallback doloop) {
105
  v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
106
  global->Set(v8::String::New("terminate"),
107
              v8::FunctionTemplate::New(terminate));
108
  global->Set(v8::String::New("fail"), v8::FunctionTemplate::New(Fail));
109
  global->Set(v8::String::New("loop"), v8::FunctionTemplate::New(Loop));
110
  global->Set(v8::String::New("doloop"), v8::FunctionTemplate::New(doloop));
111
  return global;
112
}
113

    
114

    
115
// Test that a single thread of JavaScript execution can terminate
116
// itself.
117
TEST(TerminateOnlyV8ThreadFromThreadItself) {
118
  v8::HandleScope scope(CcTest::isolate());
119
  v8::Handle<v8::ObjectTemplate> global =
120
      CreateGlobalTemplate(TerminateCurrentThread, DoLoop);
121
  v8::Handle<v8::Context> context =
122
      v8::Context::New(CcTest::isolate(), NULL, global);
123
  v8::Context::Scope context_scope(context);
124
  CHECK(!v8::V8::IsExecutionTerminating(CcTest::isolate()));
125
  // Run a loop that will be infinite if thread termination does not work.
126
  v8::Handle<v8::String> source =
127
      v8::String::New("try { loop(); fail(); } catch(e) { fail(); }");
128
  v8::Script::Compile(source)->Run();
129
  // Test that we can run the code again after thread termination.
130
  CHECK(!v8::V8::IsExecutionTerminating(CcTest::isolate()));
131
  v8::Script::Compile(source)->Run();
132
}
133

    
134

    
135
// Test that a single thread of JavaScript execution can terminate
136
// itself in a loop that performs no calls.
137
TEST(TerminateOnlyV8ThreadFromThreadItselfNoLoop) {
138
  v8::HandleScope scope(CcTest::isolate());
139
  v8::Handle<v8::ObjectTemplate> global =
140
      CreateGlobalTemplate(TerminateCurrentThread, DoLoopNoCall);
141
  v8::Handle<v8::Context> context =
142
      v8::Context::New(CcTest::isolate(), NULL, global);
143
  v8::Context::Scope context_scope(context);
144
  CHECK(!v8::V8::IsExecutionTerminating(CcTest::isolate()));
145
  // Run a loop that will be infinite if thread termination does not work.
146
  v8::Handle<v8::String> source =
147
      v8::String::New("try { loop(); fail(); } catch(e) { fail(); }");
148
  v8::Script::Compile(source)->Run();
149
  CHECK(!v8::V8::IsExecutionTerminating(CcTest::isolate()));
150
  // Test that we can run the code again after thread termination.
151
  v8::Script::Compile(source)->Run();
152
}
153

    
154

    
155
class TerminatorThread : public v8::internal::Thread {
156
 public:
157
  explicit TerminatorThread(i::Isolate* isolate)
158
      : Thread("TerminatorThread"),
159
        isolate_(reinterpret_cast<v8::Isolate*>(isolate)) { }
160
  void Run() {
161
    semaphore->Wait();
162
    CHECK(!v8::V8::IsExecutionTerminating(isolate_));
163
    v8::V8::TerminateExecution(isolate_);
164
  }
165

    
166
 private:
167
  v8::Isolate* isolate_;
168
};
169

    
170

    
171
// Test that a single thread of JavaScript execution can be terminated
172
// from the side by another thread.
173
TEST(TerminateOnlyV8ThreadFromOtherThread) {
174
  semaphore = new v8::internal::Semaphore(0);
175
  TerminatorThread thread(CcTest::i_isolate());
176
  thread.Start();
177

    
178
  v8::HandleScope scope(CcTest::isolate());
179
  v8::Handle<v8::ObjectTemplate> global = CreateGlobalTemplate(Signal, DoLoop);
180
  v8::Handle<v8::Context> context =
181
      v8::Context::New(CcTest::isolate(), NULL, global);
182
  v8::Context::Scope context_scope(context);
183
  CHECK(!v8::V8::IsExecutionTerminating(CcTest::isolate()));
184
  // Run a loop that will be infinite if thread termination does not work.
185
  v8::Handle<v8::String> source =
186
      v8::String::New("try { loop(); fail(); } catch(e) { fail(); }");
187
  v8::Script::Compile(source)->Run();
188

    
189
  thread.Join();
190
  delete semaphore;
191
  semaphore = NULL;
192
}
193

    
194

    
195
int call_count = 0;
196

    
197

    
198
void TerminateOrReturnObject(const v8::FunctionCallbackInfo<v8::Value>& args) {
199
  if (++call_count == 10) {
200
    CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate()));
201
    v8::V8::TerminateExecution(args.GetIsolate());
202
    return;
203
  }
204
  v8::Local<v8::Object> result = v8::Object::New();
205
  result->Set(v8::String::New("x"), v8::Integer::New(42));
206
  args.GetReturnValue().Set(result);
207
}
208

    
209

    
210
void LoopGetProperty(const v8::FunctionCallbackInfo<v8::Value>& args) {
211
  v8::TryCatch try_catch;
212
  CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate()));
213
  v8::Script::Compile(v8::String::New("function f() {"
214
                                      "  try {"
215
                                      "    while(true) {"
216
                                      "      terminate_or_return_object().x;"
217
                                      "    }"
218
                                      "    fail();"
219
                                      "  } catch(e) {"
220
                                      "    fail();"
221
                                      "  }"
222
                                      "}"
223
                                      "f()"))->Run();
224
  CHECK(try_catch.HasCaught());
225
  CHECK(try_catch.Exception()->IsNull());
226
  CHECK(try_catch.Message().IsEmpty());
227
  CHECK(!try_catch.CanContinue());
228
  CHECK(v8::V8::IsExecutionTerminating(args.GetIsolate()));
229
}
230

    
231

    
232
// Test that we correctly handle termination exceptions if they are
233
// triggered by the creation of error objects in connection with ICs.
234
TEST(TerminateLoadICException) {
235
  v8::HandleScope scope(CcTest::isolate());
236
  v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
237
  global->Set(v8::String::New("terminate_or_return_object"),
238
              v8::FunctionTemplate::New(TerminateOrReturnObject));
239
  global->Set(v8::String::New("fail"), v8::FunctionTemplate::New(Fail));
240
  global->Set(v8::String::New("loop"),
241
              v8::FunctionTemplate::New(LoopGetProperty));
242

    
243
  v8::Handle<v8::Context> context =
244
      v8::Context::New(CcTest::isolate(), NULL, global);
245
  v8::Context::Scope context_scope(context);
246
  CHECK(!v8::V8::IsExecutionTerminating(CcTest::isolate()));
247
  // Run a loop that will be infinite if thread termination does not work.
248
  v8::Handle<v8::String> source =
249
      v8::String::New("try { loop(); fail(); } catch(e) { fail(); }");
250
  call_count = 0;
251
  v8::Script::Compile(source)->Run();
252
  // Test that we can run the code again after thread termination.
253
  CHECK(!v8::V8::IsExecutionTerminating(CcTest::isolate()));
254
  call_count = 0;
255
  v8::Script::Compile(source)->Run();
256
}
257

    
258

    
259
void ReenterAfterTermination(const v8::FunctionCallbackInfo<v8::Value>& args) {
260
  v8::TryCatch try_catch;
261
  CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate()));
262
  v8::Script::Compile(v8::String::New("function f() {"
263
                                      "  var term = true;"
264
                                      "  try {"
265
                                      "    while(true) {"
266
                                      "      if (term) terminate();"
267
                                      "      term = false;"
268
                                      "    }"
269
                                      "    fail();"
270
                                      "  } catch(e) {"
271
                                      "    fail();"
272
                                      "  }"
273
                                      "}"
274
                                      "f()"))->Run();
275
  CHECK(try_catch.HasCaught());
276
  CHECK(try_catch.Exception()->IsNull());
277
  CHECK(try_catch.Message().IsEmpty());
278
  CHECK(!try_catch.CanContinue());
279
  CHECK(v8::V8::IsExecutionTerminating(args.GetIsolate()));
280
  v8::Script::Compile(v8::String::New("function f() { fail(); } f()"))->Run();
281
}
282

    
283

    
284
// Test that reentry into V8 while the termination exception is still pending
285
// (has not yet unwound the 0-level JS frame) does not crash.
286
TEST(TerminateAndReenterFromThreadItself) {
287
  v8::HandleScope scope(CcTest::isolate());
288
  v8::Handle<v8::ObjectTemplate> global =
289
      CreateGlobalTemplate(TerminateCurrentThread, ReenterAfterTermination);
290
  v8::Handle<v8::Context> context =
291
      v8::Context::New(CcTest::isolate(), NULL, global);
292
  v8::Context::Scope context_scope(context);
293
  CHECK(!v8::V8::IsExecutionTerminating());
294
  v8::Handle<v8::String> source =
295
      v8::String::New("try { loop(); fail(); } catch(e) { fail(); }");
296
  v8::Script::Compile(source)->Run();
297
  CHECK(!v8::V8::IsExecutionTerminating(CcTest::isolate()));
298
  // Check we can run JS again after termination.
299
  CHECK(v8::Script::Compile(v8::String::New("function f() { return true; }"
300
                                            "f()"))->Run()->IsTrue());
301
}
302

    
303

    
304
void DoLoopCancelTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
305
  v8::TryCatch try_catch;
306
  CHECK(!v8::V8::IsExecutionTerminating());
307
  v8::Script::Compile(v8::String::New("var term = true;"
308
                                      "while(true) {"
309
                                      "  if (term) terminate();"
310
                                      "  term = false;"
311
                                      "}"
312
                                      "fail();"))->Run();
313
  CHECK(try_catch.HasCaught());
314
  CHECK(try_catch.Exception()->IsNull());
315
  CHECK(try_catch.Message().IsEmpty());
316
  CHECK(!try_catch.CanContinue());
317
  CHECK(v8::V8::IsExecutionTerminating());
318
  CHECK(try_catch.HasTerminated());
319
  v8::V8::CancelTerminateExecution(CcTest::isolate());
320
  CHECK(!v8::V8::IsExecutionTerminating());
321
}
322

    
323

    
324
// Test that a single thread of JavaScript execution can terminate
325
// itself and then resume execution.
326
TEST(TerminateCancelTerminateFromThreadItself) {
327
  v8::Isolate* isolate = CcTest::isolate();
328
  v8::HandleScope scope(isolate);
329
  v8::Handle<v8::ObjectTemplate> global =
330
      CreateGlobalTemplate(TerminateCurrentThread, DoLoopCancelTerminate);
331
  v8::Handle<v8::Context> context = v8::Context::New(isolate, NULL, global);
332
  v8::Context::Scope context_scope(context);
333
  CHECK(!v8::V8::IsExecutionTerminating(CcTest::isolate()));
334
  v8::Handle<v8::String> source =
335
      v8::String::New("try { doloop(); } catch(e) { fail(); } 'completed';");
336
  // Check that execution completed with correct return value.
337
  CHECK(v8::Script::Compile(source)->Run()->Equals(v8_str("completed")));
338
}