1a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Copyright 2009 the V8 project authors. All rights reserved.
2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Redistribution and use in source and binary forms, with or without
3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// modification, are permitted provided that the following conditions are
4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// met:
5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Redistributions of source code must retain the above copyright
7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       notice, this list of conditions and the following disclaimer.
8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Redistributions in binary form must reproduce the above
9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       copyright notice, this list of conditions and the following
10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       disclaimer in the documentation and/or other materials provided
11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       with the distribution.
12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Neither the name of Google Inc. nor the names of its
13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       contributors may be used to endorse or promote products derived
14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       from this software without specific prior written permission.
15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
28b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/v8.h"
29b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "test/cctest/cctest.h"
30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
31b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/base/platform/platform.h"
32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
34b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochv8::base::Semaphore* semaphore = NULL;
35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
36b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Signal(const v8::FunctionCallbackInfo<v8::Value>& args) {
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  semaphore->Signal();
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid TerminateCurrentThread(const v8::FunctionCallbackInfo<v8::Value>& args) {
43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate()));
44b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::V8::TerminateExecution(args.GetIsolate());
45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
48b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(false);
50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
53b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Loop(const v8::FunctionCallbackInfo<v8::Value>& args) {
54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate()));
55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::String> source = v8::String::NewFromUtf8(
56b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      args.GetIsolate(), "try { doloop(); fail(); } catch(e) { fail(); }");
576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  v8::Handle<v8::Value> result = v8::Script::Compile(source)->Run();
586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  CHECK(result.IsEmpty());
59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(v8::V8::IsExecutionTerminating(args.GetIsolate()));
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
63b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid DoLoop(const v8::FunctionCallbackInfo<v8::Value>& args) {
64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::TryCatch try_catch;
65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate()));
66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Script::Compile(v8::String::NewFromUtf8(args.GetIsolate(),
67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "function f() {"
68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "  var term = true;"
69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "  try {"
70b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "    while(true) {"
71b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "      if (term) terminate();"
72b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "      term = false;"
73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "    }"
74b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "    fail();"
75b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "  } catch(e) {"
76b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "    fail();"
77b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "  }"
78b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "}"
79b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "f()"))->Run();
80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(try_catch.HasCaught());
81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(try_catch.Exception()->IsNull());
82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(try_catch.Message().IsEmpty());
83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(!try_catch.CanContinue());
84b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(v8::V8::IsExecutionTerminating(args.GetIsolate()));
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
88b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid DoLoopNoCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
89d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  v8::TryCatch try_catch;
90b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate()));
91b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Script::Compile(v8::String::NewFromUtf8(args.GetIsolate(),
92b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "var term = true;"
93b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "while(true) {"
94b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "  if (term) terminate();"
95b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "  term = false;"
96b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "}"))->Run();
97d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  CHECK(try_catch.HasCaught());
98d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  CHECK(try_catch.Exception()->IsNull());
99d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  CHECK(try_catch.Message().IsEmpty());
100d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  CHECK(!try_catch.CanContinue());
101b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(v8::V8::IsExecutionTerminating(args.GetIsolate()));
102d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
103d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
104d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockv8::Handle<v8::ObjectTemplate> CreateGlobalTemplate(
106b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    v8::Isolate* isolate,
107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    v8::FunctionCallback terminate,
108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    v8::FunctionCallback doloop) {
109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
110b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  global->Set(v8::String::NewFromUtf8(isolate, "terminate"),
111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch              v8::FunctionTemplate::New(isolate, terminate));
112b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  global->Set(v8::String::NewFromUtf8(isolate, "fail"),
113b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch              v8::FunctionTemplate::New(isolate, Fail));
114b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  global->Set(v8::String::NewFromUtf8(isolate, "loop"),
115b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch              v8::FunctionTemplate::New(isolate, Loop));
116b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  global->Set(v8::String::NewFromUtf8(isolate, "doloop"),
117b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch              v8::FunctionTemplate::New(isolate, doloop));
118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return global;
119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Test that a single thread of JavaScript execution can terminate
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// itself.
124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(TerminateOnlyV8ThreadFromThreadItself) {
125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::HandleScope scope(CcTest::isolate());
126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::Handle<v8::ObjectTemplate> global =
127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      CreateGlobalTemplate(CcTest::isolate(), TerminateCurrentThread, DoLoop);
128b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::Context> context =
129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      v8::Context::New(CcTest::isolate(), NULL, global);
130d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  v8::Context::Scope context_scope(context);
131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(!v8::V8::IsExecutionTerminating(CcTest::isolate()));
132d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Run a loop that will be infinite if thread termination does not work.
133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::String> source = v8::String::NewFromUtf8(
134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      CcTest::isolate(), "try { loop(); fail(); } catch(e) { fail(); }");
135d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  v8::Script::Compile(source)->Run();
136d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Test that we can run the code again after thread termination.
137b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(!v8::V8::IsExecutionTerminating(CcTest::isolate()));
138d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  v8::Script::Compile(source)->Run();
139d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
140d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
141d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
142d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// Test that a single thread of JavaScript execution can terminate
143d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// itself in a loop that performs no calls.
144d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockTEST(TerminateOnlyV8ThreadFromThreadItselfNoLoop) {
145b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::HandleScope scope(CcTest::isolate());
146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::ObjectTemplate> global = CreateGlobalTemplate(
147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      CcTest::isolate(), TerminateCurrentThread, DoLoopNoCall);
148b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::Context> context =
149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      v8::Context::New(CcTest::isolate(), NULL, global);
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::Context::Scope context_scope(context);
151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(!v8::V8::IsExecutionTerminating(CcTest::isolate()));
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Run a loop that will be infinite if thread termination does not work.
153b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::String> source = v8::String::NewFromUtf8(
154b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      CcTest::isolate(), "try { loop(); fail(); } catch(e) { fail(); }");
155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::Script::Compile(source)->Run();
156b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(!v8::V8::IsExecutionTerminating(CcTest::isolate()));
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Test that we can run the code again after thread termination.
158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::Script::Compile(source)->Run();
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
162b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochclass TerminatorThread : public v8::base::Thread {
16344f0eee88ff00398ff7f715fab053374d808c90dSteve Block public:
16444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  explicit TerminatorThread(i::Isolate* isolate)
165b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      : Thread(Options("TerminatorThread")),
166b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        isolate_(reinterpret_cast<v8::Isolate*>(isolate)) {}
167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void Run() {
168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    semaphore->Wait();
1693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    CHECK(!v8::V8::IsExecutionTerminating(isolate_));
1703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    v8::V8::TerminateExecution(isolate_);
171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
1733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch private:
1743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  v8::Isolate* isolate_;
175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Test that a single thread of JavaScript execution can be terminated
179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// from the side by another thread.
180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(TerminateOnlyV8ThreadFromOtherThread) {
181b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  semaphore = new v8::base::Semaphore(0);
182b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  TerminatorThread thread(CcTest::i_isolate());
183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  thread.Start();
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
185b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::HandleScope scope(CcTest::isolate());
186b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::ObjectTemplate> global =
187b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      CreateGlobalTemplate(CcTest::isolate(), Signal, DoLoop);
188b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::Context> context =
189b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      v8::Context::New(CcTest::isolate(), NULL, global);
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::Context::Scope context_scope(context);
191b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(!v8::V8::IsExecutionTerminating(CcTest::isolate()));
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Run a loop that will be infinite if thread termination does not work.
193b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::String> source = v8::String::NewFromUtf8(
194b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      CcTest::isolate(), "try { loop(); fail(); } catch(e) { fail(); }");
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::Script::Compile(source)->Run();
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  thread.Join();
198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  delete semaphore;
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  semaphore = NULL;
200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockint call_count = 0;
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
206b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid TerminateOrReturnObject(const v8::FunctionCallbackInfo<v8::Value>& args) {
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (++call_count == 10) {
208b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate()));
209b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    v8::V8::TerminateExecution(args.GetIsolate());
210b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return;
211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
212b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Local<v8::Object> result = v8::Object::New(args.GetIsolate());
213b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  result->Set(v8::String::NewFromUtf8(args.GetIsolate(), "x"),
214b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch              v8::Integer::New(args.GetIsolate(), 42));
215b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  args.GetReturnValue().Set(result);
216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
219b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid LoopGetProperty(const v8::FunctionCallbackInfo<v8::Value>& args) {
220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::TryCatch try_catch;
221b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate()));
222b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Script::Compile(
223b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      v8::String::NewFromUtf8(args.GetIsolate(),
224b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                              "function f() {"
225b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                              "  try {"
226b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                              "    while(true) {"
227b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                              "      terminate_or_return_object().x;"
228b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                              "    }"
229b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                              "    fail();"
230b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                              "  } catch(e) {"
231b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                              "    fail();"
232b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                              "  }"
233b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                              "}"
234b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                              "f()"))->Run();
235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(try_catch.HasCaught());
236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(try_catch.Exception()->IsNull());
237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(try_catch.Message().IsEmpty());
238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(!try_catch.CanContinue());
239b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(v8::V8::IsExecutionTerminating(args.GetIsolate()));
240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Test that we correctly handle termination exceptions if they are
244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// triggered by the creation of error objects in connection with ICs.
245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(TerminateLoadICException) {
246b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Isolate* isolate = CcTest::isolate();
247b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::HandleScope scope(isolate);
248b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
249b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  global->Set(
250b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      v8::String::NewFromUtf8(isolate, "terminate_or_return_object"),
251b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      v8::FunctionTemplate::New(isolate, TerminateOrReturnObject));
252b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  global->Set(v8::String::NewFromUtf8(isolate, "fail"),
253b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch              v8::FunctionTemplate::New(isolate, Fail));
254b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  global->Set(v8::String::NewFromUtf8(isolate, "loop"),
255b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch              v8::FunctionTemplate::New(isolate, LoopGetProperty));
256b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
257b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::Context> context =
258b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      v8::Context::New(isolate, NULL, global);
259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::Context::Scope context_scope(context);
260b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(!v8::V8::IsExecutionTerminating(isolate));
261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Run a loop that will be infinite if thread termination does not work.
262b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::String> source = v8::String::NewFromUtf8(
263b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      isolate, "try { loop(); fail(); } catch(e) { fail(); }");
264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  call_count = 0;
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::Script::Compile(source)->Run();
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Test that we can run the code again after thread termination.
267b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(!v8::V8::IsExecutionTerminating(isolate));
268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  call_count = 0;
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::Script::Compile(source)->Run();
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
271f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke
272b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
273b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid ReenterAfterTermination(const v8::FunctionCallbackInfo<v8::Value>& args) {
274f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  v8::TryCatch try_catch;
275b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate()));
276b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Script::Compile(v8::String::NewFromUtf8(args.GetIsolate(),
277b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "function f() {"
278b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "  var term = true;"
279b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "  try {"
280b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "    while(true) {"
281b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "      if (term) terminate();"
282b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "      term = false;"
283b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "    }"
284b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "    fail();"
285b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "  } catch(e) {"
286b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "    fail();"
287b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "  }"
288b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "}"
289b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "f()"))->Run();
290f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  CHECK(try_catch.HasCaught());
291f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  CHECK(try_catch.Exception()->IsNull());
292f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  CHECK(try_catch.Message().IsEmpty());
293f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  CHECK(!try_catch.CanContinue());
294b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(v8::V8::IsExecutionTerminating(args.GetIsolate()));
295b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Script::Compile(v8::String::NewFromUtf8(args.GetIsolate(),
296b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "function f() { fail(); } f()"))
297b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      ->Run();
298f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke}
299f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke
300b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
301f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke// Test that reentry into V8 while the termination exception is still pending
302f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke// (has not yet unwound the 0-level JS frame) does not crash.
303f7060e27768c550ace7ec48ad8c093466db52dfaLeon ClarkeTEST(TerminateAndReenterFromThreadItself) {
304b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Isolate* isolate = CcTest::isolate();
305b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::HandleScope scope(isolate);
306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::ObjectTemplate> global = CreateGlobalTemplate(
307b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      isolate, TerminateCurrentThread, ReenterAfterTermination);
308b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::Context> context =
309b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      v8::Context::New(isolate, NULL, global);
310f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  v8::Context::Scope context_scope(context);
311f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  CHECK(!v8::V8::IsExecutionTerminating());
312b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::String> source = v8::String::NewFromUtf8(
313b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      isolate, "try { loop(); fail(); } catch(e) { fail(); }");
314f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  v8::Script::Compile(source)->Run();
315b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(!v8::V8::IsExecutionTerminating(isolate));
316f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  // Check we can run JS again after termination.
317b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(v8::Script::Compile(
318b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      v8::String::NewFromUtf8(isolate,
319b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                              "function f() { return true; }"
320b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                              "f()"))
321b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            ->Run()
322b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            ->IsTrue());
323f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke}
324f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke
325b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
326b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid DoLoopCancelTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
327b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::TryCatch try_catch;
328b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(!v8::V8::IsExecutionTerminating());
329b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Script::Compile(v8::String::NewFromUtf8(args.GetIsolate(),
330b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "var term = true;"
331b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "while(true) {"
332b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "  if (term) terminate();"
333b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "  term = false;"
334b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "}"
335b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              "fail();"))->Run();
336b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(try_catch.HasCaught());
337b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(try_catch.Exception()->IsNull());
338b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(try_catch.Message().IsEmpty());
339b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(!try_catch.CanContinue());
340b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(v8::V8::IsExecutionTerminating());
341b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(try_catch.HasTerminated());
342b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::V8::CancelTerminateExecution(CcTest::isolate());
343b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(!v8::V8::IsExecutionTerminating());
344b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
345b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
346b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
347b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Test that a single thread of JavaScript execution can terminate
348b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// itself and then resume execution.
349b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochTEST(TerminateCancelTerminateFromThreadItself) {
350b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Isolate* isolate = CcTest::isolate();
351b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::HandleScope scope(isolate);
352b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::ObjectTemplate> global = CreateGlobalTemplate(
353b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      isolate, TerminateCurrentThread, DoLoopCancelTerminate);
354b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::Context> context = v8::Context::New(isolate, NULL, global);
355b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Context::Scope context_scope(context);
356b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(!v8::V8::IsExecutionTerminating(CcTest::isolate()));
357b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::String> source = v8::String::NewFromUtf8(
358b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      isolate, "try { doloop(); } catch(e) { fail(); } 'completed';");
359b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Check that execution completed with correct return value.
360b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(v8::Script::Compile(source)->Run()->Equals(v8_str("completed")));
361b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
362b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
363b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
364b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid MicrotaskShouldNotRun(const v8::FunctionCallbackInfo<v8::Value>& info) {
365b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(false);
366b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
367b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
368b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
369b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid MicrotaskLoopForever(const v8::FunctionCallbackInfo<v8::Value>& info) {
370b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Isolate* isolate = info.GetIsolate();
371b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::HandleScope scope(isolate);
372b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Enqueue another should-not-run task to ensure we clean out the queue
373b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // when we terminate.
374b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  isolate->EnqueueMicrotask(v8::Function::New(isolate, MicrotaskShouldNotRun));
375b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CompileRun("terminate(); while (true) { }");
376b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(v8::V8::IsExecutionTerminating());
377b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
378b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
379b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
380b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochTEST(TerminateFromOtherThreadWhileMicrotaskRunning) {
381b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  semaphore = new v8::base::Semaphore(0);
382b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  TerminatorThread thread(CcTest::i_isolate());
383b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  thread.Start();
384b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
385b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Isolate* isolate = CcTest::isolate();
386b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  isolate->SetAutorunMicrotasks(false);
387b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::HandleScope scope(isolate);
388b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::ObjectTemplate> global =
389b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      CreateGlobalTemplate(CcTest::isolate(), Signal, DoLoop);
390b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::Context> context =
391b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      v8::Context::New(CcTest::isolate(), NULL, global);
392b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Context::Scope context_scope(context);
393b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  isolate->EnqueueMicrotask(v8::Function::New(isolate, MicrotaskLoopForever));
394b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // The second task should never be run because we bail out if we're
395b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // terminating.
396b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  isolate->EnqueueMicrotask(v8::Function::New(isolate, MicrotaskShouldNotRun));
397b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  isolate->RunMicrotasks();
398b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
399b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::V8::CancelTerminateExecution(isolate);
400b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  isolate->RunMicrotasks();  // should not run MicrotaskShouldNotRun
401b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
402b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  thread.Join();
403b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  delete semaphore;
404b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  semaphore = NULL;
405b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
406b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
407b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
408b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochstatic int callback_counter = 0;
409b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
410b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
411b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochstatic void CounterCallback(v8::Isolate* isolate, void* data) {
412b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  callback_counter++;
413b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
414b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
415b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
416b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochTEST(PostponeTerminateException) {
417b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Isolate* isolate = CcTest::isolate();
418b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::HandleScope scope(isolate);
419b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::ObjectTemplate> global =
420b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      CreateGlobalTemplate(CcTest::isolate(), TerminateCurrentThread, DoLoop);
421b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::Context> context =
422b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      v8::Context::New(CcTest::isolate(), NULL, global);
423b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Context::Scope context_scope(context);
424b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
425b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::TryCatch try_catch;
426b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  static const char* terminate_and_loop =
427b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "terminate(); for (var i = 0; i < 10000; i++);";
428b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
429b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  { // Postpone terminate execution interrupts.
430b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    i::PostponeInterruptsScope p1(CcTest::i_isolate(),
431b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                  i::StackGuard::TERMINATE_EXECUTION) ;
432b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
433b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // API interrupts should still be triggered.
434b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    CcTest::isolate()->RequestInterrupt(&CounterCallback, NULL);
435b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    CHECK_EQ(0, callback_counter);
436b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    CompileRun(terminate_and_loop);
437b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    CHECK(!try_catch.HasTerminated());
438b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    CHECK_EQ(1, callback_counter);
439b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
440b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    { // Postpone API interrupts as well.
441b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      i::PostponeInterruptsScope p2(CcTest::i_isolate(),
442b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                    i::StackGuard::API_INTERRUPT);
443b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
444b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // None of the two interrupts should trigger.
445b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      CcTest::isolate()->RequestInterrupt(&CounterCallback, NULL);
446b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      CompileRun(terminate_and_loop);
447b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      CHECK(!try_catch.HasTerminated());
448b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      CHECK_EQ(1, callback_counter);
449b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
450b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
451b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Now the previously requested API interrupt should trigger.
452b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    CompileRun(terminate_and_loop);
453b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    CHECK(!try_catch.HasTerminated());
454b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    CHECK_EQ(2, callback_counter);
455b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
456b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
457b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Now the previously requested terminate execution interrupt should trigger.
458b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CompileRun("for (var i = 0; i < 10000; i++);");
459b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(try_catch.HasTerminated());
460b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK_EQ(2, callback_counter);
461b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
462b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
463b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
464b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochTEST(ErrorObjectAfterTermination) {
465b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Isolate* isolate = CcTest::isolate();
466b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::HandleScope scope(isolate);
467b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
468b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Context::Scope context_scope(context);
469b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::V8::TerminateExecution(isolate);
470b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8::Local<v8::Value> error = v8::Exception::Error(v8_str("error"));
471b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // TODO(yangguo): crbug/403509. Check for empty handle instead.
472b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  CHECK(error->IsUndefined());
473b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
474