OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 15 matching lines...) Expand all Loading... |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "v8.h" | 28 #include "v8.h" |
29 #include "platform.h" | 29 #include "platform.h" |
30 #include "cctest.h" | 30 #include "cctest.h" |
31 | 31 |
32 | 32 |
33 v8::internal::Semaphore* semaphore = NULL; | 33 v8::internal::Semaphore* semaphore = NULL; |
34 | 34 |
35 | 35 |
36 v8::Handle<v8::Value> Signal(const v8::Arguments& args) { | 36 void Signal(const v8::FunctionCallbackInfo<v8::Value>& args) { |
37 semaphore->Signal(); | 37 semaphore->Signal(); |
38 return v8::Undefined(); | |
39 } | 38 } |
40 | 39 |
41 | 40 |
42 v8::Handle<v8::Value> TerminateCurrentThread(const v8::Arguments& args) { | 41 void TerminateCurrentThread(const v8::FunctionCallbackInfo<v8::Value>& args) { |
43 CHECK(!v8::V8::IsExecutionTerminating()); | 42 CHECK(!v8::V8::IsExecutionTerminating()); |
44 v8::V8::TerminateExecution(); | 43 v8::V8::TerminateExecution(); |
45 return v8::Undefined(); | |
46 } | 44 } |
47 | 45 |
48 | 46 |
49 v8::Handle<v8::Value> Fail(const v8::Arguments& args) { | 47 void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) { |
50 CHECK(false); | 48 CHECK(false); |
51 return v8::Undefined(); | |
52 } | 49 } |
53 | 50 |
54 | 51 |
55 v8::Handle<v8::Value> Loop(const v8::Arguments& args) { | 52 void Loop(const v8::FunctionCallbackInfo<v8::Value>& args) { |
56 CHECK(!v8::V8::IsExecutionTerminating()); | 53 CHECK(!v8::V8::IsExecutionTerminating()); |
57 v8::Handle<v8::String> source = | 54 v8::Handle<v8::String> source = |
58 v8::String::New("try { doloop(); fail(); } catch(e) { fail(); }"); | 55 v8::String::New("try { doloop(); fail(); } catch(e) { fail(); }"); |
59 v8::Handle<v8::Value> result = v8::Script::Compile(source)->Run(); | 56 v8::Handle<v8::Value> result = v8::Script::Compile(source)->Run(); |
60 CHECK(result.IsEmpty()); | 57 CHECK(result.IsEmpty()); |
61 CHECK(v8::V8::IsExecutionTerminating()); | 58 CHECK(v8::V8::IsExecutionTerminating()); |
62 return v8::Undefined(); | |
63 } | 59 } |
64 | 60 |
65 | 61 |
66 v8::Handle<v8::Value> DoLoop(const v8::Arguments& args) { | 62 void DoLoop(const v8::FunctionCallbackInfo<v8::Value>& args) { |
67 v8::TryCatch try_catch; | 63 v8::TryCatch try_catch; |
68 CHECK(!v8::V8::IsExecutionTerminating()); | 64 CHECK(!v8::V8::IsExecutionTerminating()); |
69 v8::Script::Compile(v8::String::New("function f() {" | 65 v8::Script::Compile(v8::String::New("function f() {" |
70 " var term = true;" | 66 " var term = true;" |
71 " try {" | 67 " try {" |
72 " while(true) {" | 68 " while(true) {" |
73 " if (term) terminate();" | 69 " if (term) terminate();" |
74 " term = false;" | 70 " term = false;" |
75 " }" | 71 " }" |
76 " fail();" | 72 " fail();" |
77 " } catch(e) {" | 73 " } catch(e) {" |
78 " fail();" | 74 " fail();" |
79 " }" | 75 " }" |
80 "}" | 76 "}" |
81 "f()"))->Run(); | 77 "f()"))->Run(); |
82 CHECK(try_catch.HasCaught()); | 78 CHECK(try_catch.HasCaught()); |
83 CHECK(try_catch.Exception()->IsNull()); | 79 CHECK(try_catch.Exception()->IsNull()); |
84 CHECK(try_catch.Message().IsEmpty()); | 80 CHECK(try_catch.Message().IsEmpty()); |
85 CHECK(!try_catch.CanContinue()); | 81 CHECK(!try_catch.CanContinue()); |
86 CHECK(v8::V8::IsExecutionTerminating()); | 82 CHECK(v8::V8::IsExecutionTerminating()); |
87 return v8::Undefined(); | |
88 } | 83 } |
89 | 84 |
90 | 85 |
91 v8::Handle<v8::Value> DoLoopNoCall(const v8::Arguments& args) { | 86 void DoLoopNoCall(const v8::FunctionCallbackInfo<v8::Value>& args) { |
92 v8::TryCatch try_catch; | 87 v8::TryCatch try_catch; |
93 CHECK(!v8::V8::IsExecutionTerminating()); | 88 CHECK(!v8::V8::IsExecutionTerminating()); |
94 v8::Script::Compile(v8::String::New("var term = true;" | 89 v8::Script::Compile(v8::String::New("var term = true;" |
95 "while(true) {" | 90 "while(true) {" |
96 " if (term) terminate();" | 91 " if (term) terminate();" |
97 " term = false;" | 92 " term = false;" |
98 "}"))->Run(); | 93 "}"))->Run(); |
99 CHECK(try_catch.HasCaught()); | 94 CHECK(try_catch.HasCaught()); |
100 CHECK(try_catch.Exception()->IsNull()); | 95 CHECK(try_catch.Exception()->IsNull()); |
101 CHECK(try_catch.Message().IsEmpty()); | 96 CHECK(try_catch.Message().IsEmpty()); |
102 CHECK(!try_catch.CanContinue()); | 97 CHECK(!try_catch.CanContinue()); |
103 CHECK(v8::V8::IsExecutionTerminating()); | 98 CHECK(v8::V8::IsExecutionTerminating()); |
104 return v8::Undefined(); | |
105 } | 99 } |
106 | 100 |
107 | 101 |
108 v8::Handle<v8::ObjectTemplate> CreateGlobalTemplate( | 102 v8::Handle<v8::ObjectTemplate> CreateGlobalTemplate( |
109 v8::InvocationCallback terminate, | 103 v8::FunctionCallback terminate, |
110 v8::InvocationCallback doloop) { | 104 v8::FunctionCallback doloop) { |
111 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); | 105 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); |
112 global->Set(v8::String::New("terminate"), | 106 global->Set(v8::String::New("terminate"), |
113 v8::FunctionTemplate::New(terminate)); | 107 v8::FunctionTemplate::New(terminate)); |
114 global->Set(v8::String::New("fail"), v8::FunctionTemplate::New(Fail)); | 108 global->Set(v8::String::New("fail"), v8::FunctionTemplate::New(Fail)); |
115 global->Set(v8::String::New("loop"), v8::FunctionTemplate::New(Loop)); | 109 global->Set(v8::String::New("loop"), v8::FunctionTemplate::New(Loop)); |
116 global->Set(v8::String::New("doloop"), v8::FunctionTemplate::New(doloop)); | 110 global->Set(v8::String::New("doloop"), v8::FunctionTemplate::New(doloop)); |
117 return global; | 111 return global; |
118 } | 112 } |
119 | 113 |
120 | 114 |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 } | 255 } |
262 | 256 |
263 delete semaphore; | 257 delete semaphore; |
264 semaphore = NULL; | 258 semaphore = NULL; |
265 } | 259 } |
266 | 260 |
267 | 261 |
268 int call_count = 0; | 262 int call_count = 0; |
269 | 263 |
270 | 264 |
271 v8::Handle<v8::Value> TerminateOrReturnObject(const v8::Arguments& args) { | 265 void TerminateOrReturnObject(const v8::FunctionCallbackInfo<v8::Value>& args) { |
272 if (++call_count == 10) { | 266 if (++call_count == 10) { |
273 CHECK(!v8::V8::IsExecutionTerminating()); | 267 CHECK(!v8::V8::IsExecutionTerminating()); |
274 v8::V8::TerminateExecution(); | 268 v8::V8::TerminateExecution(); |
275 return v8::Undefined(); | 269 return; |
276 } | 270 } |
277 v8::Local<v8::Object> result = v8::Object::New(); | 271 v8::Local<v8::Object> result = v8::Object::New(); |
278 result->Set(v8::String::New("x"), v8::Integer::New(42)); | 272 result->Set(v8::String::New("x"), v8::Integer::New(42)); |
279 return result; | 273 args.GetReturnValue().Set(result); |
280 } | 274 } |
281 | 275 |
282 | 276 |
283 v8::Handle<v8::Value> LoopGetProperty(const v8::Arguments& args) { | 277 void LoopGetProperty(const v8::FunctionCallbackInfo<v8::Value>& args) { |
284 v8::TryCatch try_catch; | 278 v8::TryCatch try_catch; |
285 CHECK(!v8::V8::IsExecutionTerminating()); | 279 CHECK(!v8::V8::IsExecutionTerminating()); |
286 v8::Script::Compile(v8::String::New("function f() {" | 280 v8::Script::Compile(v8::String::New("function f() {" |
287 " try {" | 281 " try {" |
288 " while(true) {" | 282 " while(true) {" |
289 " terminate_or_return_object().x;" | 283 " terminate_or_return_object().x;" |
290 " }" | 284 " }" |
291 " fail();" | 285 " fail();" |
292 " } catch(e) {" | 286 " } catch(e) {" |
293 " fail();" | 287 " fail();" |
294 " }" | 288 " }" |
295 "}" | 289 "}" |
296 "f()"))->Run(); | 290 "f()"))->Run(); |
297 CHECK(try_catch.HasCaught()); | 291 CHECK(try_catch.HasCaught()); |
298 CHECK(try_catch.Exception()->IsNull()); | 292 CHECK(try_catch.Exception()->IsNull()); |
299 CHECK(try_catch.Message().IsEmpty()); | 293 CHECK(try_catch.Message().IsEmpty()); |
300 CHECK(!try_catch.CanContinue()); | 294 CHECK(!try_catch.CanContinue()); |
301 CHECK(v8::V8::IsExecutionTerminating()); | 295 CHECK(v8::V8::IsExecutionTerminating()); |
302 return v8::Undefined(); | |
303 } | 296 } |
304 | 297 |
305 | 298 |
306 // Test that we correctly handle termination exceptions if they are | 299 // Test that we correctly handle termination exceptions if they are |
307 // triggered by the creation of error objects in connection with ICs. | 300 // triggered by the creation of error objects in connection with ICs. |
308 TEST(TerminateLoadICException) { | 301 TEST(TerminateLoadICException) { |
309 v8::HandleScope scope(v8::Isolate::GetCurrent()); | 302 v8::HandleScope scope(v8::Isolate::GetCurrent()); |
310 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); | 303 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); |
311 global->Set(v8::String::New("terminate_or_return_object"), | 304 global->Set(v8::String::New("terminate_or_return_object"), |
312 v8::FunctionTemplate::New(TerminateOrReturnObject)); | 305 v8::FunctionTemplate::New(TerminateOrReturnObject)); |
313 global->Set(v8::String::New("fail"), v8::FunctionTemplate::New(Fail)); | 306 global->Set(v8::String::New("fail"), v8::FunctionTemplate::New(Fail)); |
314 global->Set(v8::String::New("loop"), | 307 global->Set(v8::String::New("loop"), |
315 v8::FunctionTemplate::New(LoopGetProperty)); | 308 v8::FunctionTemplate::New(LoopGetProperty)); |
316 | 309 |
317 v8::Handle<v8::Context> context = | 310 v8::Handle<v8::Context> context = |
318 v8::Context::New(v8::Isolate::GetCurrent(), NULL, global); | 311 v8::Context::New(v8::Isolate::GetCurrent(), NULL, global); |
319 v8::Context::Scope context_scope(context); | 312 v8::Context::Scope context_scope(context); |
320 CHECK(!v8::V8::IsExecutionTerminating()); | 313 CHECK(!v8::V8::IsExecutionTerminating()); |
321 // Run a loop that will be infinite if thread termination does not work. | 314 // Run a loop that will be infinite if thread termination does not work. |
322 v8::Handle<v8::String> source = | 315 v8::Handle<v8::String> source = |
323 v8::String::New("try { loop(); fail(); } catch(e) { fail(); }"); | 316 v8::String::New("try { loop(); fail(); } catch(e) { fail(); }"); |
324 call_count = 0; | 317 call_count = 0; |
325 v8::Script::Compile(source)->Run(); | 318 v8::Script::Compile(source)->Run(); |
326 // Test that we can run the code again after thread termination. | 319 // Test that we can run the code again after thread termination. |
327 CHECK(!v8::V8::IsExecutionTerminating()); | 320 CHECK(!v8::V8::IsExecutionTerminating()); |
328 call_count = 0; | 321 call_count = 0; |
329 v8::Script::Compile(source)->Run(); | 322 v8::Script::Compile(source)->Run(); |
330 } | 323 } |
331 | 324 |
332 v8::Handle<v8::Value> ReenterAfterTermination(const v8::Arguments& args) { | 325 void ReenterAfterTermination(const v8::FunctionCallbackInfo<v8::Value>& args) { |
333 v8::TryCatch try_catch; | 326 v8::TryCatch try_catch; |
334 CHECK(!v8::V8::IsExecutionTerminating()); | 327 CHECK(!v8::V8::IsExecutionTerminating()); |
335 v8::Script::Compile(v8::String::New("function f() {" | 328 v8::Script::Compile(v8::String::New("function f() {" |
336 " var term = true;" | 329 " var term = true;" |
337 " try {" | 330 " try {" |
338 " while(true) {" | 331 " while(true) {" |
339 " if (term) terminate();" | 332 " if (term) terminate();" |
340 " term = false;" | 333 " term = false;" |
341 " }" | 334 " }" |
342 " fail();" | 335 " fail();" |
343 " } catch(e) {" | 336 " } catch(e) {" |
344 " fail();" | 337 " fail();" |
345 " }" | 338 " }" |
346 "}" | 339 "}" |
347 "f()"))->Run(); | 340 "f()"))->Run(); |
348 CHECK(try_catch.HasCaught()); | 341 CHECK(try_catch.HasCaught()); |
349 CHECK(try_catch.Exception()->IsNull()); | 342 CHECK(try_catch.Exception()->IsNull()); |
350 CHECK(try_catch.Message().IsEmpty()); | 343 CHECK(try_catch.Message().IsEmpty()); |
351 CHECK(!try_catch.CanContinue()); | 344 CHECK(!try_catch.CanContinue()); |
352 CHECK(v8::V8::IsExecutionTerminating()); | 345 CHECK(v8::V8::IsExecutionTerminating()); |
353 v8::Script::Compile(v8::String::New("function f() { fail(); } f()"))->Run(); | 346 v8::Script::Compile(v8::String::New("function f() { fail(); } f()"))->Run(); |
354 return v8::Undefined(); | |
355 } | 347 } |
356 | 348 |
357 // Test that reentry into V8 while the termination exception is still pending | 349 // 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. | 350 // (has not yet unwound the 0-level JS frame) does not crash. |
359 TEST(TerminateAndReenterFromThreadItself) { | 351 TEST(TerminateAndReenterFromThreadItself) { |
360 v8::HandleScope scope(v8::Isolate::GetCurrent()); | 352 v8::HandleScope scope(v8::Isolate::GetCurrent()); |
361 v8::Handle<v8::ObjectTemplate> global = | 353 v8::Handle<v8::ObjectTemplate> global = |
362 CreateGlobalTemplate(TerminateCurrentThread, ReenterAfterTermination); | 354 CreateGlobalTemplate(TerminateCurrentThread, ReenterAfterTermination); |
363 v8::Handle<v8::Context> context = | 355 v8::Handle<v8::Context> context = |
364 v8::Context::New(v8::Isolate::GetCurrent(), NULL, global); | 356 v8::Context::New(v8::Isolate::GetCurrent(), NULL, global); |
365 v8::Context::Scope context_scope(context); | 357 v8::Context::Scope context_scope(context); |
366 CHECK(!v8::V8::IsExecutionTerminating()); | 358 CHECK(!v8::V8::IsExecutionTerminating()); |
367 v8::Handle<v8::String> source = | 359 v8::Handle<v8::String> source = |
368 v8::String::New("try { loop(); fail(); } catch(e) { fail(); }"); | 360 v8::String::New("try { loop(); fail(); } catch(e) { fail(); }"); |
369 v8::Script::Compile(source)->Run(); | 361 v8::Script::Compile(source)->Run(); |
370 CHECK(!v8::V8::IsExecutionTerminating()); | 362 CHECK(!v8::V8::IsExecutionTerminating()); |
371 // Check we can run JS again after termination. | 363 // Check we can run JS again after termination. |
372 CHECK(v8::Script::Compile(v8::String::New("function f() { return true; }" | 364 CHECK(v8::Script::Compile(v8::String::New("function f() { return true; }" |
373 "f()"))->Run()->IsTrue()); | 365 "f()"))->Run()->IsTrue()); |
374 } | 366 } |
375 | 367 |
376 v8::Handle<v8::Value> DoLoopCancelTerminate(const v8::Arguments& args) { | 368 void DoLoopCancelTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) { |
377 v8::TryCatch try_catch; | 369 v8::TryCatch try_catch; |
378 CHECK(!v8::V8::IsExecutionTerminating()); | 370 CHECK(!v8::V8::IsExecutionTerminating()); |
379 v8::Script::Compile(v8::String::New("var term = true;" | 371 v8::Script::Compile(v8::String::New("var term = true;" |
380 "while(true) {" | 372 "while(true) {" |
381 " if (term) terminate();" | 373 " if (term) terminate();" |
382 " term = false;" | 374 " term = false;" |
383 "}" | 375 "}" |
384 "fail();"))->Run(); | 376 "fail();"))->Run(); |
385 CHECK(try_catch.HasCaught()); | 377 CHECK(try_catch.HasCaught()); |
386 CHECK(try_catch.Exception()->IsNull()); | 378 CHECK(try_catch.Exception()->IsNull()); |
387 CHECK(try_catch.Message().IsEmpty()); | 379 CHECK(try_catch.Message().IsEmpty()); |
388 CHECK(!try_catch.CanContinue()); | 380 CHECK(!try_catch.CanContinue()); |
389 CHECK(v8::V8::IsExecutionTerminating()); | 381 CHECK(v8::V8::IsExecutionTerminating()); |
390 CHECK(try_catch.HasTerminated()); | 382 CHECK(try_catch.HasTerminated()); |
391 v8::V8::CancelTerminateExecution(v8::Isolate::GetCurrent()); | 383 v8::V8::CancelTerminateExecution(v8::Isolate::GetCurrent()); |
392 CHECK(!v8::V8::IsExecutionTerminating()); | 384 CHECK(!v8::V8::IsExecutionTerminating()); |
393 return v8::Undefined(); | |
394 } | 385 } |
395 | 386 |
396 // Test that a single thread of JavaScript execution can terminate | 387 // Test that a single thread of JavaScript execution can terminate |
397 // itself and then resume execution. | 388 // itself and then resume execution. |
398 TEST(TerminateCancelTerminateFromThreadItself) { | 389 TEST(TerminateCancelTerminateFromThreadItself) { |
399 v8::HandleScope scope; | 390 v8::HandleScope scope; |
400 v8::Handle<v8::ObjectTemplate> global = | 391 v8::Handle<v8::ObjectTemplate> global = |
401 CreateGlobalTemplate(TerminateCurrentThread, DoLoopCancelTerminate); | 392 CreateGlobalTemplate(TerminateCurrentThread, DoLoopCancelTerminate); |
402 v8::Handle<v8::Context> context = | 393 v8::Handle<v8::Context> context = |
403 v8::Context::New(v8::Isolate::GetCurrent(), NULL, global); | 394 v8::Context::New(v8::Isolate::GetCurrent(), NULL, global); |
404 v8::Context::Scope context_scope(context); | 395 v8::Context::Scope context_scope(context); |
405 CHECK(!v8::V8::IsExecutionTerminating()); | 396 CHECK(!v8::V8::IsExecutionTerminating()); |
406 v8::Handle<v8::String> source = | 397 v8::Handle<v8::String> source = |
407 v8::String::New("try { doloop(); } catch(e) { fail(); } 'completed';"); | 398 v8::String::New("try { doloop(); } catch(e) { fail(); } 'completed';"); |
408 // Check that execution completed with correct return value. | 399 // Check that execution completed with correct return value. |
409 CHECK(v8::Script::Compile(source)->Run()->Equals(v8_str("completed"))); | 400 CHECK(v8::Script::Compile(source)->Run()->Equals(v8_str("completed"))); |
410 } | 401 } |
411 | 402 |
OLD | NEW |