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 |