OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 | 215 |
216 // Static state for stack guards. | 216 // Static state for stack guards. |
217 StackGuard::ThreadLocal StackGuard::thread_local_; | 217 StackGuard::ThreadLocal StackGuard::thread_local_; |
218 | 218 |
219 | 219 |
220 StackGuard::StackGuard() { | 220 StackGuard::StackGuard() { |
221 // NOTE: Overall the StackGuard code assumes that the stack grows towards | 221 // NOTE: Overall the StackGuard code assumes that the stack grows towards |
222 // lower addresses. | 222 // lower addresses. |
223 ExecutionAccess access; | 223 ExecutionAccess access; |
224 if (thread_local_.nesting_++ == 0) { | 224 if (thread_local_.nesting_++ == 0) { |
225 // Initial StackGuard is being set. We will set the stack limits based on | 225 // Initial StackGuard is being set. |
226 // the current stack pointer allowing the stack to grow kLimitSize from | |
227 // here. | |
228 | 226 |
229 // Ensure that either the stack limits are unset (kIllegalLimit) or that | 227 // Ensure that either the stack limits are unset (kIllegalLimit) or that |
230 // they indicate a pending interruption. The interrupt limit will be | 228 // they indicate a pending interruption. The interrupt limit will be |
231 // temporarily reset through the code below and reestablished if the | 229 // temporarily reset through the code below and reestablished if the |
232 // interrupt flags indicate that an interrupt is pending. | 230 // interrupt flags indicate that an interrupt is pending. |
233 ASSERT(thread_local_.jslimit_ == kIllegalLimit || | 231 ASSERT(thread_local_.jslimit_ == kIllegalLimit || |
234 (thread_local_.jslimit_ == kInterruptLimit && | 232 (thread_local_.jslimit_ == kInterruptLimit && |
235 thread_local_.interrupt_flags_ != 0)); | 233 thread_local_.interrupt_flags_ != 0)); |
236 ASSERT(thread_local_.climit_ == kIllegalLimit || | 234 ASSERT(thread_local_.climit_ == kIllegalLimit || |
237 (thread_local_.climit_ == kInterruptLimit && | 235 (thread_local_.climit_ == kInterruptLimit && |
238 thread_local_.interrupt_flags_ != 0)); | 236 thread_local_.interrupt_flags_ != 0)); |
239 | 237 |
240 uintptr_t limit = GENERATED_CODE_STACK_LIMIT(kLimitSize); | 238 if (thread_local_.initial_jslimit_ == kIllegalLimit || |
241 thread_local_.initial_jslimit_ = thread_local_.jslimit_ = limit; | 239 thread_local_.initial_climit_ == kIllegalLimit) { |
242 Heap::SetStackLimit(limit); | 240 ASSERT(thread_local_.initial_jslimit_ == kIllegalLimit && |
243 // NOTE: The check for overflow is not safe as there is no guarantee that | 241 thread_local_.initial_climit_ == kIllegalLimit); |
244 // the running thread has its stack in all memory up to address 0x00000000. | |
245 thread_local_.initial_climit_ = thread_local_.climit_ = | |
246 reinterpret_cast<uintptr_t>(this) >= kLimitSize ? | |
247 reinterpret_cast<uintptr_t>(this) - kLimitSize : 0; | |
248 | 242 |
249 if (thread_local_.interrupt_flags_ != 0) { | 243 // We will set the stack limits based on the current stack |
250 set_limits(kInterruptLimit, access); | 244 // pointer allowing the stack to grow kLimitSize from here. |
| 245 |
| 246 // Compute default limit, checking for underflow. |
| 247 uintptr_t limit = |
| 248 reinterpret_cast<uintptr_t>(this) >= kLimitSize ? |
| 249 reinterpret_cast<uintptr_t>(this) - kLimitSize : 0; |
| 250 |
| 251 thread_local_.initial_jslimit_ = GENERATED_CODE_STACK_LIMIT(limit); |
| 252 thread_local_.initial_climit_ = limit; |
| 253 } |
| 254 |
| 255 if (thread_local_.interrupt_flags_ == 0) { |
| 256 set_limits(thread_local_.initial_jslimit_, thread_local_.initial_climit_, |
| 257 access); |
251 } | 258 } |
252 } | 259 } |
253 // Ensure that proper limits have been set. | 260 // Ensure that proper limits have been set. |
254 ASSERT(thread_local_.jslimit_ != kIllegalLimit && | 261 ASSERT(thread_local_.jslimit_ != kIllegalLimit && |
255 thread_local_.climit_ != kIllegalLimit); | 262 thread_local_.climit_ != kIllegalLimit); |
256 ASSERT(thread_local_.initial_jslimit_ != kIllegalLimit && | 263 ASSERT(thread_local_.initial_jslimit_ != kIllegalLimit && |
257 thread_local_.initial_climit_ != kIllegalLimit); | 264 thread_local_.initial_climit_ != kIllegalLimit); |
258 } | 265 } |
259 | 266 |
260 | 267 |
261 StackGuard::~StackGuard() { | 268 StackGuard::~StackGuard() { |
262 ExecutionAccess access; | 269 ExecutionAccess access; |
263 if (--thread_local_.nesting_ == 0) { | 270 if (--thread_local_.nesting_ == 0 && |
264 set_limits(kIllegalLimit, access); | 271 thread_local_.interrupt_flags_ == 0) { |
| 272 set_illegal_limit(access); |
265 } | 273 } |
266 } | 274 } |
267 | 275 |
268 | 276 |
269 bool StackGuard::IsStackOverflow() { | 277 bool StackGuard::IsStackOverflow() { |
270 ExecutionAccess access; | 278 ExecutionAccess access; |
271 return (thread_local_.jslimit_ != kInterruptLimit && | 279 return (thread_local_.jslimit_ != kInterruptLimit && |
272 thread_local_.climit_ != kInterruptLimit); | 280 thread_local_.climit_ != kInterruptLimit); |
273 } | 281 } |
274 | 282 |
275 | 283 |
276 void StackGuard::EnableInterrupts() { | 284 void StackGuard::EnableInterrupts() { |
277 ExecutionAccess access; | 285 ExecutionAccess access; |
278 if (IsSet(access)) { | 286 if (IsSet(access)) { |
279 set_limits(kInterruptLimit, access); | 287 set_interrupt_limit(access); |
280 } | 288 } |
281 } | 289 } |
282 | 290 |
283 | 291 |
284 void StackGuard::SetStackLimit(uintptr_t limit) { | 292 void StackGuard::SetStackLimit(uintptr_t limit) { |
285 ExecutionAccess access; | 293 ExecutionAccess access; |
286 // If the current limits are special (eg due to a pending interrupt) then | 294 thread_local_.initial_jslimit_ = GENERATED_CODE_STACK_LIMIT(limit); |
287 // leave them alone. | 295 thread_local_.initial_climit_ = limit; |
288 if (thread_local_.jslimit_ == thread_local_.initial_jslimit_) { | 296 |
289 thread_local_.jslimit_ = limit; | 297 // If a StackGuard is active (nesting_ > 0) and not interrupted set |
290 Heap::SetStackLimit(limit); | 298 // the limit directly. Otherwise the limit will be established by |
| 299 // the first StackGuard. |
| 300 if (thread_local_.nesting_ > 0 && |
| 301 thread_local_.interrupt_flags_ == 0) { |
| 302 set_limits(thread_local_.initial_jslimit_, thread_local_.initial_climit_, |
| 303 access); |
291 } | 304 } |
292 if (thread_local_.climit_ == thread_local_.initial_climit_) { | |
293 thread_local_.climit_ = limit; | |
294 } | |
295 thread_local_.initial_climit_ = limit; | |
296 thread_local_.initial_jslimit_ = limit; | |
297 } | 305 } |
298 | 306 |
299 | 307 |
300 void StackGuard::DisableInterrupts() { | 308 void StackGuard::DisableInterrupts() { |
301 ExecutionAccess access; | 309 ExecutionAccess access; |
302 reset_limits(access); | 310 reset_limits(access); |
303 } | 311 } |
304 | 312 |
305 | 313 |
306 bool StackGuard::IsSet(const ExecutionAccess& lock) { | 314 bool StackGuard::IsSet(const ExecutionAccess& lock) { |
307 return thread_local_.interrupt_flags_ != 0; | 315 return thread_local_.interrupt_flags_ != 0; |
308 } | 316 } |
309 | 317 |
310 | 318 |
311 bool StackGuard::IsInterrupted() { | 319 bool StackGuard::IsInterrupted() { |
312 ExecutionAccess access; | 320 ExecutionAccess access; |
313 return thread_local_.interrupt_flags_ & INTERRUPT; | 321 return thread_local_.interrupt_flags_ & INTERRUPT; |
314 } | 322 } |
315 | 323 |
316 | 324 |
317 void StackGuard::Interrupt() { | 325 void StackGuard::Interrupt() { |
318 ExecutionAccess access; | 326 ExecutionAccess access; |
319 thread_local_.interrupt_flags_ |= INTERRUPT; | 327 thread_local_.interrupt_flags_ |= INTERRUPT; |
320 set_limits(kInterruptLimit, access); | 328 set_interrupt_limit(access); |
321 } | 329 } |
322 | 330 |
323 | 331 |
324 bool StackGuard::IsPreempted() { | 332 bool StackGuard::IsPreempted() { |
325 ExecutionAccess access; | 333 ExecutionAccess access; |
326 return thread_local_.interrupt_flags_ & PREEMPT; | 334 return thread_local_.interrupt_flags_ & PREEMPT; |
327 } | 335 } |
328 | 336 |
329 | 337 |
330 void StackGuard::Preempt() { | 338 void StackGuard::Preempt() { |
331 ExecutionAccess access; | 339 ExecutionAccess access; |
332 thread_local_.interrupt_flags_ |= PREEMPT; | 340 thread_local_.interrupt_flags_ |= PREEMPT; |
333 set_limits(kInterruptLimit, access); | 341 set_interrupt_limit(access); |
334 } | 342 } |
335 | 343 |
336 | 344 |
337 bool StackGuard::IsTerminateExecution() { | 345 bool StackGuard::IsTerminateExecution() { |
338 ExecutionAccess access; | 346 ExecutionAccess access; |
339 return thread_local_.interrupt_flags_ & TERMINATE; | 347 return thread_local_.interrupt_flags_ & TERMINATE; |
340 } | 348 } |
341 | 349 |
342 | 350 |
343 void StackGuard::TerminateExecution() { | 351 void StackGuard::TerminateExecution() { |
344 ExecutionAccess access; | 352 ExecutionAccess access; |
345 thread_local_.interrupt_flags_ |= TERMINATE; | 353 thread_local_.interrupt_flags_ |= TERMINATE; |
346 set_limits(kInterruptLimit, access); | 354 set_interrupt_limit(access); |
347 } | 355 } |
348 | 356 |
349 | 357 |
350 #ifdef ENABLE_DEBUGGER_SUPPORT | 358 #ifdef ENABLE_DEBUGGER_SUPPORT |
351 bool StackGuard::IsDebugBreak() { | 359 bool StackGuard::IsDebugBreak() { |
352 ExecutionAccess access; | 360 ExecutionAccess access; |
353 return thread_local_.interrupt_flags_ & DEBUGBREAK; | 361 return thread_local_.interrupt_flags_ & DEBUGBREAK; |
354 } | 362 } |
355 | 363 |
356 | 364 |
357 void StackGuard::DebugBreak() { | 365 void StackGuard::DebugBreak() { |
358 ExecutionAccess access; | 366 ExecutionAccess access; |
359 thread_local_.interrupt_flags_ |= DEBUGBREAK; | 367 thread_local_.interrupt_flags_ |= DEBUGBREAK; |
360 set_limits(kInterruptLimit, access); | 368 set_interrupt_limit(access); |
361 } | 369 } |
362 | 370 |
363 | 371 |
364 bool StackGuard::IsDebugCommand() { | 372 bool StackGuard::IsDebugCommand() { |
365 ExecutionAccess access; | 373 ExecutionAccess access; |
366 return thread_local_.interrupt_flags_ & DEBUGCOMMAND; | 374 return thread_local_.interrupt_flags_ & DEBUGCOMMAND; |
367 } | 375 } |
368 | 376 |
369 | 377 |
370 void StackGuard::DebugCommand() { | 378 void StackGuard::DebugCommand() { |
371 if (FLAG_debugger_auto_break) { | 379 if (FLAG_debugger_auto_break) { |
372 ExecutionAccess access; | 380 ExecutionAccess access; |
373 thread_local_.interrupt_flags_ |= DEBUGCOMMAND; | 381 thread_local_.interrupt_flags_ |= DEBUGCOMMAND; |
374 set_limits(kInterruptLimit, access); | 382 set_interrupt_limit(access); |
375 } | 383 } |
376 } | 384 } |
377 #endif | 385 #endif |
378 | 386 |
379 void StackGuard::Continue(InterruptFlag after_what) { | 387 void StackGuard::Continue(InterruptFlag after_what) { |
380 ExecutionAccess access; | 388 ExecutionAccess access; |
381 thread_local_.interrupt_flags_ &= ~static_cast<int>(after_what); | 389 thread_local_.interrupt_flags_ &= ~static_cast<int>(after_what); |
382 if (thread_local_.interrupt_flags_ == 0) { | 390 if (thread_local_.interrupt_flags_ == 0) { |
383 reset_limits(access); | 391 reset_limits(access); |
384 } | 392 } |
(...skipping 15 matching lines...) Expand all Loading... |
400 | 408 |
401 | 409 |
402 char* StackGuard::RestoreStackGuard(char* from) { | 410 char* StackGuard::RestoreStackGuard(char* from) { |
403 ExecutionAccess access; | 411 ExecutionAccess access; |
404 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal)); | 412 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal)); |
405 Heap::SetStackLimit(thread_local_.jslimit_); | 413 Heap::SetStackLimit(thread_local_.jslimit_); |
406 return from + sizeof(ThreadLocal); | 414 return from + sizeof(ThreadLocal); |
407 } | 415 } |
408 | 416 |
409 | 417 |
| 418 void StackGuard::InitThread(const ExecutionAccess& lock) { |
| 419 // new threads should configure their own stack limits |
| 420 ThreadLocal blank; |
| 421 thread_local_ = blank; |
| 422 } |
| 423 |
| 424 |
410 // --- C a l l s t o n a t i v e s --- | 425 // --- C a l l s t o n a t i v e s --- |
411 | 426 |
412 #define RETURN_NATIVE_CALL(name, argc, argv, has_pending_exception) \ | 427 #define RETURN_NATIVE_CALL(name, argc, argv, has_pending_exception) \ |
413 do { \ | 428 do { \ |
414 Object** args[argc] = argv; \ | 429 Object** args[argc] = argv; \ |
415 ASSERT(has_pending_exception != NULL); \ | 430 ASSERT(has_pending_exception != NULL); \ |
416 return Call(Top::name##_fun(), Top::builtins(), argc, args, \ | 431 return Call(Top::name##_fun(), Top::builtins(), argc, args, \ |
417 has_pending_exception); \ | 432 has_pending_exception); \ |
418 } while (false) | 433 } while (false) |
419 | 434 |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
685 // All allocation spaces other than NEW_SPACE have the same effect. | 700 // All allocation spaces other than NEW_SPACE have the same effect. |
686 Heap::CollectAllGarbage(false); | 701 Heap::CollectAllGarbage(false); |
687 return v8::Undefined(); | 702 return v8::Undefined(); |
688 } | 703 } |
689 | 704 |
690 | 705 |
691 static GCExtension kGCExtension; | 706 static GCExtension kGCExtension; |
692 v8::DeclareExtension kGCExtensionDeclaration(&kGCExtension); | 707 v8::DeclareExtension kGCExtensionDeclaration(&kGCExtension); |
693 | 708 |
694 } } // namespace v8::internal | 709 } } // namespace v8::internal |
OLD | NEW |