| 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 22 matching lines...) Expand all Loading... |
| 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 v8::Handle<v8::Value> Signal(const v8::Arguments& args) { |
| 37 semaphore->Signal(); | 37 semaphore->Signal(); |
| 38 return v8::Undefined(); | 38 return v8::Undefined(); |
| 39 } | 39 } |
| 40 | 40 |
| 41 | 41 |
| 42 v8::Handle<v8::Value> TerminateCurrentThread(const v8::Arguments& args) { | 42 v8::Handle<v8::Value> TerminateCurrentThread(const v8::Arguments& args) { |
| 43 CHECK(!v8::V8::IsExecutionTerminating()); | |
| 44 v8::V8::TerminateExecution(); | 43 v8::V8::TerminateExecution(); |
| 45 return v8::Undefined(); | 44 return v8::Undefined(); |
| 46 } | 45 } |
| 47 | 46 |
| 48 | 47 |
| 49 v8::Handle<v8::Value> Fail(const v8::Arguments& args) { | 48 v8::Handle<v8::Value> Fail(const v8::Arguments& args) { |
| 50 CHECK(false); | 49 CHECK(false); |
| 51 return v8::Undefined(); | 50 return v8::Undefined(); |
| 52 } | 51 } |
| 53 | 52 |
| 54 | 53 |
| 55 v8::Handle<v8::Value> Loop(const v8::Arguments& args) { | 54 v8::Handle<v8::Value> Loop(const v8::Arguments& args) { |
| 56 CHECK(!v8::V8::IsExecutionTerminating()); | |
| 57 v8::Handle<v8::String> source = | 55 v8::Handle<v8::String> source = |
| 58 v8::String::New("try { doloop(); fail(); } catch(e) { fail(); }"); | 56 v8::String::New("try { doloop(); fail(); } catch(e) { fail(); }"); |
| 59 v8::Handle<v8::Value> result = v8::Script::Compile(source)->Run(); | 57 v8::Script::Compile(source)->Run(); |
| 60 CHECK(result.IsEmpty()); | |
| 61 CHECK(v8::V8::IsExecutionTerminating()); | |
| 62 return v8::Undefined(); | 58 return v8::Undefined(); |
| 63 } | 59 } |
| 64 | 60 |
| 65 | 61 |
| 66 v8::Handle<v8::Value> DoLoop(const v8::Arguments& args) { | 62 v8::Handle<v8::Value> DoLoop(const v8::Arguments& args) { |
| 67 v8::TryCatch try_catch; | 63 v8::TryCatch try_catch; |
| 68 CHECK(!v8::V8::IsExecutionTerminating()); | |
| 69 v8::Script::Compile(v8::String::New("function f() {" | 64 v8::Script::Compile(v8::String::New("function f() {" |
| 70 " var term = true;" | 65 " var term = true;" |
| 71 " try {" | 66 " try {" |
| 72 " while(true) {" | 67 " while(true) {" |
| 73 " if (term) terminate();" | 68 " if (term) terminate();" |
| 74 " term = false;" | 69 " term = false;" |
| 75 " }" | 70 " }" |
| 76 " fail();" | 71 " fail();" |
| 77 " } catch(e) {" | 72 " } catch(e) {" |
| 78 " fail();" | 73 " fail();" |
| 79 " }" | 74 " }" |
| 80 "}" | 75 "}" |
| 81 "f()"))->Run(); | 76 "f()"))->Run(); |
| 82 CHECK(try_catch.HasCaught()); | 77 CHECK(try_catch.HasCaught()); |
| 83 CHECK(try_catch.Exception()->IsNull()); | 78 CHECK(try_catch.Exception()->IsNull()); |
| 84 CHECK(try_catch.Message().IsEmpty()); | 79 CHECK(try_catch.Message().IsEmpty()); |
| 85 CHECK(!try_catch.CanContinue()); | 80 CHECK(!try_catch.CanContinue()); |
| 86 CHECK(v8::V8::IsExecutionTerminating()); | |
| 87 return v8::Undefined(); | 81 return v8::Undefined(); |
| 88 } | 82 } |
| 89 | 83 |
| 90 | 84 |
| 91 v8::Handle<v8::Value> DoLoopNoCall(const v8::Arguments& args) { | 85 v8::Handle<v8::Value> DoLoopNoCall(const v8::Arguments& args) { |
| 92 v8::TryCatch try_catch; | 86 v8::TryCatch try_catch; |
| 93 CHECK(!v8::V8::IsExecutionTerminating()); | |
| 94 v8::Script::Compile(v8::String::New("var term = true;" | 87 v8::Script::Compile(v8::String::New("var term = true;" |
| 95 "while(true) {" | 88 "while(true) {" |
| 96 " if (term) terminate();" | 89 " if (term) terminate();" |
| 97 " term = false;" | 90 " term = false;" |
| 98 "}"))->Run(); | 91 "}"))->Run(); |
| 99 CHECK(try_catch.HasCaught()); | 92 CHECK(try_catch.HasCaught()); |
| 100 CHECK(try_catch.Exception()->IsNull()); | 93 CHECK(try_catch.Exception()->IsNull()); |
| 101 CHECK(try_catch.Message().IsEmpty()); | 94 CHECK(try_catch.Message().IsEmpty()); |
| 102 CHECK(!try_catch.CanContinue()); | 95 CHECK(!try_catch.CanContinue()); |
| 103 CHECK(v8::V8::IsExecutionTerminating()); | |
| 104 return v8::Undefined(); | 96 return v8::Undefined(); |
| 105 } | 97 } |
| 106 | 98 |
| 107 | 99 |
| 108 v8::Handle<v8::ObjectTemplate> CreateGlobalTemplate( | 100 v8::Handle<v8::ObjectTemplate> CreateGlobalTemplate( |
| 109 v8::InvocationCallback terminate, | 101 v8::InvocationCallback terminate, |
| 110 v8::InvocationCallback doloop) { | 102 v8::InvocationCallback doloop) { |
| 111 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); | 103 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); |
| 112 global->Set(v8::String::New("terminate"), | 104 global->Set(v8::String::New("terminate"), |
| 113 v8::FunctionTemplate::New(terminate)); | 105 v8::FunctionTemplate::New(terminate)); |
| 114 global->Set(v8::String::New("fail"), v8::FunctionTemplate::New(Fail)); | 106 global->Set(v8::String::New("fail"), v8::FunctionTemplate::New(Fail)); |
| 115 global->Set(v8::String::New("loop"), v8::FunctionTemplate::New(Loop)); | 107 global->Set(v8::String::New("loop"), v8::FunctionTemplate::New(Loop)); |
| 116 global->Set(v8::String::New("doloop"), v8::FunctionTemplate::New(doloop)); | 108 global->Set(v8::String::New("doloop"), v8::FunctionTemplate::New(doloop)); |
| 117 return global; | 109 return global; |
| 118 } | 110 } |
| 119 | 111 |
| 120 | 112 |
| 121 // Test that a single thread of JavaScript execution can terminate | 113 // Test that a single thread of JavaScript execution can terminate |
| 122 // itself. | 114 // itself. |
| 123 TEST(TerminateOnlyV8ThreadFromThreadItself) { | 115 TEST(TerminateOnlyV8ThreadFromThreadItself) { |
| 124 v8::HandleScope scope; | 116 v8::HandleScope scope; |
| 125 v8::Handle<v8::ObjectTemplate> global = | 117 v8::Handle<v8::ObjectTemplate> global = |
| 126 CreateGlobalTemplate(TerminateCurrentThread, DoLoop); | 118 CreateGlobalTemplate(TerminateCurrentThread, DoLoop); |
| 127 v8::Persistent<v8::Context> context = v8::Context::New(NULL, global); | 119 v8::Persistent<v8::Context> context = v8::Context::New(NULL, global); |
| 128 v8::Context::Scope context_scope(context); | 120 v8::Context::Scope context_scope(context); |
| 129 CHECK(!v8::V8::IsExecutionTerminating()); | |
| 130 // Run a loop that will be infinite if thread termination does not work. | 121 // Run a loop that will be infinite if thread termination does not work. |
| 131 v8::Handle<v8::String> source = | 122 v8::Handle<v8::String> source = |
| 132 v8::String::New("try { loop(); fail(); } catch(e) { fail(); }"); | 123 v8::String::New("try { loop(); fail(); } catch(e) { fail(); }"); |
| 133 v8::Script::Compile(source)->Run(); | 124 v8::Script::Compile(source)->Run(); |
| 134 // Test that we can run the code again after thread termination. | 125 // Test that we can run the code again after thread termination. |
| 135 CHECK(!v8::V8::IsExecutionTerminating()); | |
| 136 v8::Script::Compile(source)->Run(); | 126 v8::Script::Compile(source)->Run(); |
| 137 context.Dispose(); | 127 context.Dispose(); |
| 138 } | 128 } |
| 139 | 129 |
| 140 | 130 |
| 141 // Test that a single thread of JavaScript execution can terminate | 131 // Test that a single thread of JavaScript execution can terminate |
| 142 // itself in a loop that performs no calls. | 132 // itself in a loop that performs no calls. |
| 143 TEST(TerminateOnlyV8ThreadFromThreadItselfNoLoop) { | 133 TEST(TerminateOnlyV8ThreadFromThreadItselfNoLoop) { |
| 144 v8::HandleScope scope; | 134 v8::HandleScope scope; |
| 145 v8::Handle<v8::ObjectTemplate> global = | 135 v8::Handle<v8::ObjectTemplate> global = |
| 146 CreateGlobalTemplate(TerminateCurrentThread, DoLoopNoCall); | 136 CreateGlobalTemplate(TerminateCurrentThread, DoLoopNoCall); |
| 147 v8::Persistent<v8::Context> context = v8::Context::New(NULL, global); | 137 v8::Persistent<v8::Context> context = v8::Context::New(NULL, global); |
| 148 v8::Context::Scope context_scope(context); | 138 v8::Context::Scope context_scope(context); |
| 149 CHECK(!v8::V8::IsExecutionTerminating()); | |
| 150 // Run a loop that will be infinite if thread termination does not work. | 139 // Run a loop that will be infinite if thread termination does not work. |
| 151 v8::Handle<v8::String> source = | 140 v8::Handle<v8::String> source = |
| 152 v8::String::New("try { loop(); fail(); } catch(e) { fail(); }"); | 141 v8::String::New("try { loop(); fail(); } catch(e) { fail(); }"); |
| 153 v8::Script::Compile(source)->Run(); | 142 v8::Script::Compile(source)->Run(); |
| 154 CHECK(!v8::V8::IsExecutionTerminating()); | |
| 155 // Test that we can run the code again after thread termination. | 143 // Test that we can run the code again after thread termination. |
| 156 v8::Script::Compile(source)->Run(); | 144 v8::Script::Compile(source)->Run(); |
| 157 context.Dispose(); | 145 context.Dispose(); |
| 158 } | 146 } |
| 159 | 147 |
| 160 | 148 |
| 161 class TerminatorThread : public v8::internal::Thread { | 149 class TerminatorThread : public v8::internal::Thread { |
| 162 void Run() { | 150 void Run() { |
| 163 semaphore->Wait(); | 151 semaphore->Wait(); |
| 164 CHECK(!v8::V8::IsExecutionTerminating()); | |
| 165 v8::V8::TerminateExecution(); | 152 v8::V8::TerminateExecution(); |
| 166 } | 153 } |
| 167 }; | 154 }; |
| 168 | 155 |
| 169 | 156 |
| 170 // Test that a single thread of JavaScript execution can be terminated | 157 // Test that a single thread of JavaScript execution can be terminated |
| 171 // from the side by another thread. | 158 // from the side by another thread. |
| 172 TEST(TerminateOnlyV8ThreadFromOtherThread) { | 159 TEST(TerminateOnlyV8ThreadFromOtherThread) { |
| 173 semaphore = v8::internal::OS::CreateSemaphore(0); | 160 semaphore = v8::internal::OS::CreateSemaphore(0); |
| 174 TerminatorThread thread; | 161 TerminatorThread thread; |
| 175 thread.Start(); | 162 thread.Start(); |
| 176 | 163 |
| 177 v8::HandleScope scope; | 164 v8::HandleScope scope; |
| 178 v8::Handle<v8::ObjectTemplate> global = CreateGlobalTemplate(Signal, DoLoop); | 165 v8::Handle<v8::ObjectTemplate> global = CreateGlobalTemplate(Signal, DoLoop); |
| 179 v8::Persistent<v8::Context> context = v8::Context::New(NULL, global); | 166 v8::Persistent<v8::Context> context = v8::Context::New(NULL, global); |
| 180 v8::Context::Scope context_scope(context); | 167 v8::Context::Scope context_scope(context); |
| 181 CHECK(!v8::V8::IsExecutionTerminating()); | |
| 182 // Run a loop that will be infinite if thread termination does not work. | 168 // Run a loop that will be infinite if thread termination does not work. |
| 183 v8::Handle<v8::String> source = | 169 v8::Handle<v8::String> source = |
| 184 v8::String::New("try { loop(); fail(); } catch(e) { fail(); }"); | 170 v8::String::New("try { loop(); fail(); } catch(e) { fail(); }"); |
| 185 v8::Script::Compile(source)->Run(); | 171 v8::Script::Compile(source)->Run(); |
| 186 | 172 |
| 187 thread.Join(); | 173 thread.Join(); |
| 188 delete semaphore; | 174 delete semaphore; |
| 189 semaphore = NULL; | 175 semaphore = NULL; |
| 190 context.Dispose(); | 176 context.Dispose(); |
| 191 } | 177 } |
| 192 | 178 |
| 193 | 179 |
| 194 class LoopingThread : public v8::internal::Thread { | 180 class LoopingThread : public v8::internal::Thread { |
| 195 public: | 181 public: |
| 196 void Run() { | 182 void Run() { |
| 197 v8::Locker locker; | 183 v8::Locker locker; |
| 198 v8::HandleScope scope; | 184 v8::HandleScope scope; |
| 199 v8_thread_id_ = v8::V8::GetCurrentThreadId(); | 185 v8_thread_id_ = v8::V8::GetCurrentThreadId(); |
| 200 v8::Handle<v8::ObjectTemplate> global = | 186 v8::Handle<v8::ObjectTemplate> global = |
| 201 CreateGlobalTemplate(Signal, DoLoop); | 187 CreateGlobalTemplate(Signal, DoLoop); |
| 202 v8::Persistent<v8::Context> context = v8::Context::New(NULL, global); | 188 v8::Persistent<v8::Context> context = v8::Context::New(NULL, global); |
| 203 v8::Context::Scope context_scope(context); | 189 v8::Context::Scope context_scope(context); |
| 204 CHECK(!v8::V8::IsExecutionTerminating()); | |
| 205 // Run a loop that will be infinite if thread termination does not work. | 190 // Run a loop that will be infinite if thread termination does not work. |
| 206 v8::Handle<v8::String> source = | 191 v8::Handle<v8::String> source = |
| 207 v8::String::New("try { loop(); fail(); } catch(e) { fail(); }"); | 192 v8::String::New("try { loop(); fail(); } catch(e) { fail(); }"); |
| 208 v8::Script::Compile(source)->Run(); | 193 v8::Script::Compile(source)->Run(); |
| 209 context.Dispose(); | 194 context.Dispose(); |
| 210 } | 195 } |
| 211 | 196 |
| 212 int GetV8ThreadId() { return v8_thread_id_; } | 197 int GetV8ThreadId() { return v8_thread_id_; } |
| 213 | 198 |
| 214 private: | 199 private: |
| (...skipping 28 matching lines...) Expand all Loading... |
| 243 delete semaphore; | 228 delete semaphore; |
| 244 semaphore = NULL; | 229 semaphore = NULL; |
| 245 } | 230 } |
| 246 | 231 |
| 247 | 232 |
| 248 int call_count = 0; | 233 int call_count = 0; |
| 249 | 234 |
| 250 | 235 |
| 251 v8::Handle<v8::Value> TerminateOrReturnObject(const v8::Arguments& args) { | 236 v8::Handle<v8::Value> TerminateOrReturnObject(const v8::Arguments& args) { |
| 252 if (++call_count == 10) { | 237 if (++call_count == 10) { |
| 253 CHECK(!v8::V8::IsExecutionTerminating()); | |
| 254 v8::V8::TerminateExecution(); | 238 v8::V8::TerminateExecution(); |
| 255 return v8::Undefined(); | 239 return v8::Undefined(); |
| 256 } | 240 } |
| 257 v8::Local<v8::Object> result = v8::Object::New(); | 241 v8::Local<v8::Object> result = v8::Object::New(); |
| 258 result->Set(v8::String::New("x"), v8::Integer::New(42)); | 242 result->Set(v8::String::New("x"), v8::Integer::New(42)); |
| 259 return result; | 243 return result; |
| 260 } | 244 } |
| 261 | 245 |
| 262 | 246 |
| 263 v8::Handle<v8::Value> LoopGetProperty(const v8::Arguments& args) { | 247 v8::Handle<v8::Value> LoopGetProperty(const v8::Arguments& args) { |
| 264 v8::TryCatch try_catch; | 248 v8::TryCatch try_catch; |
| 265 CHECK(!v8::V8::IsExecutionTerminating()); | |
| 266 v8::Script::Compile(v8::String::New("function f() {" | 249 v8::Script::Compile(v8::String::New("function f() {" |
| 267 " try {" | 250 " try {" |
| 268 " while(true) {" | 251 " while(true) {" |
| 269 " terminate_or_return_object().x;" | 252 " terminate_or_return_object().x;" |
| 270 " }" | 253 " }" |
| 271 " fail();" | 254 " fail();" |
| 272 " } catch(e) {" | 255 " } catch(e) {" |
| 273 " fail();" | 256 " fail();" |
| 274 " }" | 257 " }" |
| 275 "}" | 258 "}" |
| 276 "f()"))->Run(); | 259 "f()"))->Run(); |
| 277 CHECK(try_catch.HasCaught()); | 260 CHECK(try_catch.HasCaught()); |
| 278 CHECK(try_catch.Exception()->IsNull()); | 261 CHECK(try_catch.Exception()->IsNull()); |
| 279 CHECK(try_catch.Message().IsEmpty()); | 262 CHECK(try_catch.Message().IsEmpty()); |
| 280 CHECK(!try_catch.CanContinue()); | 263 CHECK(!try_catch.CanContinue()); |
| 281 CHECK(v8::V8::IsExecutionTerminating()); | |
| 282 return v8::Undefined(); | 264 return v8::Undefined(); |
| 283 } | 265 } |
| 284 | 266 |
| 285 | 267 |
| 286 // Test that we correctly handle termination exceptions if they are | 268 // Test that we correctly handle termination exceptions if they are |
| 287 // triggered by the creation of error objects in connection with ICs. | 269 // triggered by the creation of error objects in connection with ICs. |
| 288 TEST(TerminateLoadICException) { | 270 TEST(TerminateLoadICException) { |
| 289 v8::HandleScope scope; | 271 v8::HandleScope scope; |
| 290 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); | 272 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); |
| 291 global->Set(v8::String::New("terminate_or_return_object"), | 273 global->Set(v8::String::New("terminate_or_return_object"), |
| 292 v8::FunctionTemplate::New(TerminateOrReturnObject)); | 274 v8::FunctionTemplate::New(TerminateOrReturnObject)); |
| 293 global->Set(v8::String::New("fail"), v8::FunctionTemplate::New(Fail)); | 275 global->Set(v8::String::New("fail"), v8::FunctionTemplate::New(Fail)); |
| 294 global->Set(v8::String::New("loop"), | 276 global->Set(v8::String::New("loop"), |
| 295 v8::FunctionTemplate::New(LoopGetProperty)); | 277 v8::FunctionTemplate::New(LoopGetProperty)); |
| 296 | 278 |
| 297 v8::Persistent<v8::Context> context = v8::Context::New(NULL, global); | 279 v8::Persistent<v8::Context> context = v8::Context::New(NULL, global); |
| 298 v8::Context::Scope context_scope(context); | 280 v8::Context::Scope context_scope(context); |
| 299 CHECK(!v8::V8::IsExecutionTerminating()); | |
| 300 // Run a loop that will be infinite if thread termination does not work. | 281 // Run a loop that will be infinite if thread termination does not work. |
| 301 v8::Handle<v8::String> source = | 282 v8::Handle<v8::String> source = |
| 302 v8::String::New("try { loop(); fail(); } catch(e) { fail(); }"); | 283 v8::String::New("try { loop(); fail(); } catch(e) { fail(); }"); |
| 303 call_count = 0; | 284 call_count = 0; |
| 304 v8::Script::Compile(source)->Run(); | 285 v8::Script::Compile(source)->Run(); |
| 305 // Test that we can run the code again after thread termination. | 286 // Test that we can run the code again after thread termination. |
| 306 CHECK(!v8::V8::IsExecutionTerminating()); | |
| 307 call_count = 0; | 287 call_count = 0; |
| 308 v8::Script::Compile(source)->Run(); | 288 v8::Script::Compile(source)->Run(); |
| 309 context.Dispose(); | 289 context.Dispose(); |
| 310 } | 290 } |
| OLD | NEW |