v8  3.14.5(node0.10.28)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
test-thread-termination.cc
Go to the documentation of this file.
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 
34 
35 
37  semaphore->Signal();
38  return v8::Undefined();
39 }
40 
41 
45  return v8::Undefined();
46 }
47 
48 
50  CHECK(false);
51  return v8::Undefined();
52 }
53 
54 
57  v8::Handle<v8::String> source =
58  v8::String::New("try { doloop(); fail(); } catch(e) { fail(); }");
59  v8::Handle<v8::Value> result = v8::Script::Compile(source)->Run();
60  CHECK(result.IsEmpty());
62  return v8::Undefined();
63 }
64 
65 
67  v8::TryCatch try_catch;
69  v8::Script::Compile(v8::String::New("function f() {"
70  " var term = true;"
71  " try {"
72  " while(true) {"
73  " if (term) terminate();"
74  " term = false;"
75  " }"
76  " fail();"
77  " } catch(e) {"
78  " fail();"
79  " }"
80  "}"
81  "f()"))->Run();
82  CHECK(try_catch.HasCaught());
83  CHECK(try_catch.Exception()->IsNull());
84  CHECK(try_catch.Message().IsEmpty());
85  CHECK(!try_catch.CanContinue());
87  return v8::Undefined();
88 }
89 
90 
92  v8::TryCatch try_catch;
94  v8::Script::Compile(v8::String::New("var term = true;"
95  "while(true) {"
96  " if (term) terminate();"
97  " term = false;"
98  "}"))->Run();
99  CHECK(try_catch.HasCaught());
100  CHECK(try_catch.Exception()->IsNull());
101  CHECK(try_catch.Message().IsEmpty());
102  CHECK(!try_catch.CanContinue());
104  return v8::Undefined();
105 }
106 
107 
109  v8::InvocationCallback terminate,
110  v8::InvocationCallback doloop) {
112  global->Set(v8::String::New("terminate"),
113  v8::FunctionTemplate::New(terminate));
116  global->Set(v8::String::New("doloop"), v8::FunctionTemplate::New(doloop));
117  return global;
118 }
119 
120 
121 // Test that a single thread of JavaScript execution can terminate
122 // itself.
123 TEST(TerminateOnlyV8ThreadFromThreadItself) {
124  v8::HandleScope scope;
128  v8::Context::Scope context_scope(context);
130  // Run a loop that will be infinite if thread termination does not work.
131  v8::Handle<v8::String> source =
132  v8::String::New("try { loop(); fail(); } catch(e) { fail(); }");
133  v8::Script::Compile(source)->Run();
134  // Test that we can run the code again after thread termination.
136  v8::Script::Compile(source)->Run();
137  context.Dispose();
138 }
139 
140 
141 // Test that a single thread of JavaScript execution can terminate
142 // itself in a loop that performs no calls.
143 TEST(TerminateOnlyV8ThreadFromThreadItselfNoLoop) {
144  v8::HandleScope scope;
148  v8::Context::Scope context_scope(context);
150  // Run a loop that will be infinite if thread termination does not work.
151  v8::Handle<v8::String> source =
152  v8::String::New("try { loop(); fail(); } catch(e) { fail(); }");
153  v8::Script::Compile(source)->Run();
155  // Test that we can run the code again after thread termination.
156  v8::Script::Compile(source)->Run();
157  context.Dispose();
158 }
159 
160 
162  public:
163  explicit TerminatorThread(i::Isolate* isolate)
164  : Thread("TerminatorThread"),
165  isolate_(reinterpret_cast<v8::Isolate*>(isolate)) { }
166  void Run() {
167  semaphore->Wait();
169  v8::V8::TerminateExecution(isolate_);
170  }
171 
172  private:
173  v8::Isolate* isolate_;
174 };
175 
176 
177 // Test that a single thread of JavaScript execution can be terminated
178 // from the side by another thread.
179 TEST(TerminateOnlyV8ThreadFromOtherThread) {
180  semaphore = v8::internal::OS::CreateSemaphore(0);
181  TerminatorThread thread(i::Isolate::Current());
182  thread.Start();
183 
184  v8::HandleScope scope;
187  v8::Context::Scope context_scope(context);
189  // Run a loop that will be infinite if thread termination does not work.
190  v8::Handle<v8::String> source =
191  v8::String::New("try { loop(); fail(); } catch(e) { fail(); }");
192  v8::Script::Compile(source)->Run();
193 
194  thread.Join();
195  delete semaphore;
196  semaphore = NULL;
197  context.Dispose();
198 }
199 
200 
202  public:
203  LoopingThread() : Thread("LoopingThread") { }
204  void Run() {
205  v8::Locker locker;
206  v8::HandleScope scope;
207  v8_thread_id_ = v8::V8::GetCurrentThreadId();
211  v8::Context::Scope context_scope(context);
213  // Run a loop that will be infinite if thread termination does not work.
214  v8::Handle<v8::String> source =
215  v8::String::New("try { loop(); fail(); } catch(e) { fail(); }");
216  v8::Script::Compile(source)->Run();
217  context.Dispose();
218  }
219 
220  int GetV8ThreadId() { return v8_thread_id_; }
221 
222  private:
223  int v8_thread_id_;
224 };
225 
226 
227 // Test that multiple threads using default isolate can be terminated
228 // from another thread when using Lockers and preemption.
229 TEST(TerminateMultipleV8ThreadsDefaultIsolate) {
230  {
231  v8::Locker locker;
234  semaphore = v8::internal::OS::CreateSemaphore(0);
235  }
236  const int kThreads = 2;
237  i::List<LoopingThread*> threads(kThreads);
238  for (int i = 0; i < kThreads; i++) {
239  threads.Add(new LoopingThread());
240  }
241  for (int i = 0; i < kThreads; i++) {
242  threads[i]->Start();
243  }
244  // Wait until all threads have signaled the semaphore.
245  for (int i = 0; i < kThreads; i++) {
246  semaphore->Wait();
247  }
248  {
249  v8::Locker locker;
250  for (int i = 0; i < kThreads; i++) {
251  v8::V8::TerminateExecution(threads[i]->GetV8ThreadId());
252  }
253  }
254  for (int i = 0; i < kThreads; i++) {
255  threads[i]->Join();
256  delete threads[i];
257  }
258  {
259  v8::Locker locker;
261  }
262 
263  delete semaphore;
264  semaphore = NULL;
265 }
266 
267 
268 int call_count = 0;
269 
270 
272  if (++call_count == 10) {
275  return v8::Undefined();
276  }
278  result->Set(v8::String::New("x"), v8::Integer::New(42));
279  return result;
280 }
281 
282 
284  v8::TryCatch try_catch;
286  v8::Script::Compile(v8::String::New("function f() {"
287  " try {"
288  " while(true) {"
289  " terminate_or_return_object().x;"
290  " }"
291  " fail();"
292  " } catch(e) {"
293  " fail();"
294  " }"
295  "}"
296  "f()"))->Run();
297  CHECK(try_catch.HasCaught());
298  CHECK(try_catch.Exception()->IsNull());
299  CHECK(try_catch.Message().IsEmpty());
300  CHECK(!try_catch.CanContinue());
302  return v8::Undefined();
303 }
304 
305 
306 // Test that we correctly handle termination exceptions if they are
307 // triggered by the creation of error objects in connection with ICs.
308 TEST(TerminateLoadICException) {
309  v8::HandleScope scope;
311  global->Set(v8::String::New("terminate_or_return_object"),
314  global->Set(v8::String::New("loop"),
316 
318  v8::Context::Scope context_scope(context);
320  // Run a loop that will be infinite if thread termination does not work.
321  v8::Handle<v8::String> source =
322  v8::String::New("try { loop(); fail(); } catch(e) { fail(); }");
323  call_count = 0;
324  v8::Script::Compile(source)->Run();
325  // Test that we can run the code again after thread termination.
327  call_count = 0;
328  v8::Script::Compile(source)->Run();
329  context.Dispose();
330 }
331 
333  v8::TryCatch try_catch;
335  v8::Script::Compile(v8::String::New("function f() {"
336  " var term = true;"
337  " try {"
338  " while(true) {"
339  " if (term) terminate();"
340  " term = false;"
341  " }"
342  " fail();"
343  " } catch(e) {"
344  " fail();"
345  " }"
346  "}"
347  "f()"))->Run();
348  CHECK(try_catch.HasCaught());
349  CHECK(try_catch.Exception()->IsNull());
350  CHECK(try_catch.Message().IsEmpty());
351  CHECK(!try_catch.CanContinue());
353  v8::Script::Compile(v8::String::New("function f() { fail(); } f()"))->Run();
354  return v8::Undefined();
355 }
356 
357 // Test that reentry into V8 while the termination exception is still pending
358 // (has not yet unwound the 0-level JS frame) does not crash.
359 TEST(TerminateAndReenterFromThreadItself) {
360  v8::HandleScope scope;
364  v8::Context::Scope context_scope(context);
366  v8::Handle<v8::String> source =
367  v8::String::New("try { loop(); fail(); } catch(e) { fail(); }");
368  v8::Script::Compile(source)->Run();
370  // Check we can run JS again after termination.
371  CHECK(v8::Script::Compile(v8::String::New("function f() { return true; }"
372  "f()"))->Run()->IsTrue());
373  context.Dispose();
374 }
375 
static Local< Script > Compile(Handle< String > source, ScriptOrigin *origin=NULL, ScriptData *pre_data=NULL, Handle< String > script_data=Handle< String >())
Definition: api.cc:1568
TerminatorThread(i::Isolate *isolate)
static bool IsExecutionTerminating(Isolate *isolate=NULL)
Definition: api.cc:5513
v8::Handle< v8::Value > Fail(const v8::Arguments &args)
static Local< FunctionTemplate > New(InvocationCallback callback=0, Handle< Value > data=Handle< Value >(), Handle< Signature > signature=Handle< Signature >())
Definition: api.cc:951
void Dispose()
Definition: v8.h:4235
Thread(const Options &options)
v8::Handle< v8::Value > TerminateOrReturnObject(const v8::Arguments &args)
Local< Value > Exception() const
Definition: api.cc:1720
v8::Handle< v8::Value > TerminateCurrentThread(const v8::Arguments &args)
v8::Handle< v8::Value > DoLoopNoCall(const v8::Arguments &args)
bool HasCaught() const
Definition: api.cc:1703
static V8EXPORT Local< String > New(const char *data, int length=-1)
Definition: api.cc:4779
v8::Handle< v8::Value > ReenterAfterTermination(const v8::Arguments &args)
#define CHECK(condition)
Definition: checks.h:56
v8::Handle< v8::ObjectTemplate > CreateGlobalTemplate(v8::InvocationCallback terminate, v8::InvocationCallback doloop)
void Set(Handle< String > name, Handle< Data > value, PropertyAttribute attributes=None)
Definition: api.cc:902
v8::Handle< v8::Value > DoLoop(const v8::Arguments &args)
Handle< Value >(* InvocationCallback)(const Arguments &args)
Definition: v8.h:2047
static Local< ObjectTemplate > New()
Definition: api.cc:1253
static void TerminateExecution(int thread_id)
Definition: api.cc:5487
v8::Handle< v8::Value > LoopGetProperty(const v8::Arguments &args)
bool CanContinue() const
Definition: api.cc:1708
static Semaphore * CreateSemaphore(int count)
v8::Handle< v8::Value > Signal(const v8::Arguments &args)
static int GetCurrentThreadId()
Definition: api.cc:5480
virtual void Signal()=0
v8::Handle< v8::Value > Loop(const v8::Arguments &args)
static V8EXPORT Local< Integer > New(int32_t value)
Definition: api.cc:5228
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if NULL
static void StartPreemption(int every_n_ms)
Definition: v8threads.cc:142
Handle< Primitive > V8EXPORT Undefined()
Definition: api.cc:549
virtual void Wait()=0
void Add(const T &element, AllocationPolicy allocator=AllocationPolicy())
Definition: list-inl.h:38
bool IsEmpty() const
Definition: v8.h:209
static Persistent< Context > New(ExtensionConfiguration *extensions=NULL, Handle< ObjectTemplate > global_template=Handle< ObjectTemplate >(), Handle< Value > global_object=Handle< Value >())
Definition: api.cc:4411
static void StopPreemption()
Definition: v8threads.cc:147
TEST(TerminateOnlyV8ThreadFromThreadItself)
Definition: v8.h:106
Local< v8::Message > Message() const
Definition: api.cc:1750
v8::internal::Semaphore * semaphore
static bool Initialize()
Definition: api.cc:4269
static V8EXPORT Local< Object > New()
Definition: api.cc:4957
V8EXPORT bool Set(Handle< Value > key, Handle< Value > value, PropertyAttribute attribs=None)
Definition: api.cc:2765