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 20 matching lines...) Expand all Loading... |
31 | 31 |
32 #include "api.h" | 32 #include "api.h" |
33 #include "codegen-inl.h" | 33 #include "codegen-inl.h" |
34 #include "debug.h" | 34 #include "debug.h" |
35 #include "simulator.h" | 35 #include "simulator.h" |
36 #include "v8threads.h" | 36 #include "v8threads.h" |
37 | 37 |
38 namespace v8 { | 38 namespace v8 { |
39 namespace internal { | 39 namespace internal { |
40 | 40 |
| 41 class StackGuardPrivateData { |
| 42 public: |
| 43 Thread::LocalStorageKey stack_limit_key; |
| 44 |
| 45 StackGuardPrivateData() |
| 46 :stack_limit_key(internal::Thread::CreateThreadLocalKey()) { |
| 47 } |
| 48 }; |
| 49 |
| 50 StackGuardData::StackGuardData() |
| 51 :thread_local_(0), |
| 52 stack_guard_private_data_(NULL) { |
| 53 } |
41 | 54 |
42 static Handle<Object> Invoke(bool construct, | 55 static Handle<Object> Invoke(bool construct, |
43 Handle<JSFunction> func, | 56 Handle<JSFunction> func, |
44 Handle<Object> receiver, | 57 Handle<Object> receiver, |
45 int argc, | 58 int argc, |
46 Object*** args, | 59 Object*** args, |
47 bool* has_pending_exception) { | 60 bool* has_pending_exception) { |
48 // Make sure we have a real function, not a boilerplate function. | 61 // Make sure we have a real function, not a boilerplate function. |
49 ASSERT(!func->IsBoilerplate()); | 62 ASSERT(!func->IsBoilerplate()); |
50 | 63 |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 HeapObject::cast(*object)->map()->has_instance_call_handler()) { | 210 HeapObject::cast(*object)->map()->has_instance_call_handler()) { |
198 return Handle<JSFunction>( | 211 return Handle<JSFunction>( |
199 Top::global_context()->call_as_constructor_delegate()); | 212 Top::global_context()->call_as_constructor_delegate()); |
200 } | 213 } |
201 | 214 |
202 return Factory::undefined_value(); | 215 return Factory::undefined_value(); |
203 } | 216 } |
204 | 217 |
205 | 218 |
206 // Static state for stack guards. | 219 // Static state for stack guards. |
207 StackGuard::ThreadLocal StackGuard::thread_local_; | |
208 | 220 |
209 | 221 |
210 bool StackGuard::IsStackOverflow() { | 222 bool StackGuard::IsStackOverflow() { |
211 ExecutionAccess access; | 223 ExecutionAccess access; |
212 return (thread_local_.jslimit_ != kInterruptLimit && | 224 StackGuardData::ThreadLocal& thread_local = v8_context()-> |
213 thread_local_.climit_ != kInterruptLimit); | 225 stack_guard_data_.thread_local_; |
| 226 return (thread_local.jslimit_ != kInterruptLimit && |
| 227 thread_local.climit_ != kInterruptLimit); |
214 } | 228 } |
215 | 229 |
216 | 230 |
217 void StackGuard::EnableInterrupts() { | 231 void StackGuard::EnableInterrupts() { |
218 ExecutionAccess access; | 232 ExecutionAccess access; |
219 if (IsSet(access)) { | 233 if (IsSet(access)) { |
220 set_limits(kInterruptLimit, access); | 234 set_limits(kInterruptLimit, access); |
221 } | 235 } |
222 } | 236 } |
223 | 237 |
224 | 238 |
225 void StackGuard::SetStackLimit(uintptr_t limit) { | 239 void StackGuard::SetStackLimit(uintptr_t limit) { |
226 ExecutionAccess access; | 240 ExecutionAccess access; |
| 241 StackGuardData::ThreadLocal& thread_local = v8_context()-> |
| 242 stack_guard_data_.thread_local_; |
227 // If the current limits are special (eg due to a pending interrupt) then | 243 // If the current limits are special (eg due to a pending interrupt) then |
228 // leave them alone. | 244 // leave them alone. |
229 uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(limit); | 245 uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(limit); |
230 if (thread_local_.jslimit_ == thread_local_.real_jslimit_) { | 246 if (thread_local.jslimit_ == thread_local.real_jslimit_) { |
231 thread_local_.jslimit_ = jslimit; | 247 thread_local.jslimit_ = jslimit; |
232 } | 248 } |
233 if (thread_local_.climit_ == thread_local_.real_climit_) { | 249 if (thread_local.climit_ == thread_local.real_climit_) { |
234 thread_local_.climit_ = limit; | 250 thread_local.climit_ = limit; |
235 } | 251 } |
236 thread_local_.real_climit_ = limit; | 252 thread_local.real_climit_ = limit; |
237 thread_local_.real_jslimit_ = jslimit; | 253 thread_local.real_jslimit_ = jslimit; |
238 } | 254 } |
239 | 255 |
240 | 256 |
241 void StackGuard::DisableInterrupts() { | 257 void StackGuard::DisableInterrupts() { |
242 ExecutionAccess access; | 258 ExecutionAccess access; |
243 reset_limits(access); | 259 reset_limits(access); |
244 } | 260 } |
245 | 261 |
246 | 262 |
247 bool StackGuard::IsSet(const ExecutionAccess& lock) { | 263 bool StackGuard::IsSet(const ExecutionAccess& lock) { |
248 return thread_local_.interrupt_flags_ != 0; | 264 return v8_context()->stack_guard_data_.thread_local_.interrupt_flags_ != 0; |
249 } | 265 } |
250 | 266 |
251 | 267 |
252 bool StackGuard::IsInterrupted() { | 268 bool StackGuard::IsInterrupted() { |
253 ExecutionAccess access; | 269 ExecutionAccess access; |
254 return thread_local_.interrupt_flags_ & INTERRUPT; | 270 return v8_context()-> |
| 271 stack_guard_data_.thread_local_.interrupt_flags_ & INTERRUPT; |
255 } | 272 } |
256 | 273 |
257 | 274 |
258 void StackGuard::Interrupt() { | 275 void StackGuard::Interrupt() { |
259 ExecutionAccess access; | 276 ExecutionAccess access; |
260 thread_local_.interrupt_flags_ |= INTERRUPT; | 277 v8_context()->stack_guard_data_.thread_local_.interrupt_flags_ |= INTERRUPT; |
261 set_limits(kInterruptLimit, access); | 278 set_limits(kInterruptLimit, access); |
262 } | 279 } |
263 | 280 |
264 | 281 |
265 bool StackGuard::IsPreempted() { | 282 bool StackGuard::IsPreempted() { |
266 ExecutionAccess access; | 283 ExecutionAccess access; |
267 return thread_local_.interrupt_flags_ & PREEMPT; | 284 return v8_context()-> |
| 285 stack_guard_data_.thread_local_.interrupt_flags_ & PREEMPT; |
268 } | 286 } |
269 | 287 |
270 | 288 |
271 void StackGuard::Preempt() { | 289 void StackGuard::Preempt() { |
272 ExecutionAccess access; | 290 ExecutionAccess access; |
273 thread_local_.interrupt_flags_ |= PREEMPT; | 291 v8_context()->stack_guard_data_.thread_local_.interrupt_flags_ |= PREEMPT; |
274 set_limits(kInterruptLimit, access); | 292 set_limits(kInterruptLimit, access); |
275 } | 293 } |
276 | 294 |
277 | 295 |
278 bool StackGuard::IsTerminateExecution() { | 296 bool StackGuard::IsTerminateExecution() { |
279 ExecutionAccess access; | 297 ExecutionAccess access; |
280 return thread_local_.interrupt_flags_ & TERMINATE; | 298 return v8_context()-> |
| 299 stack_guard_data_.thread_local_.interrupt_flags_ & TERMINATE; |
281 } | 300 } |
282 | 301 |
283 | 302 |
284 void StackGuard::TerminateExecution() { | 303 void StackGuard::TerminateExecution() { |
285 ExecutionAccess access; | 304 ExecutionAccess access; |
286 thread_local_.interrupt_flags_ |= TERMINATE; | 305 v8_context()->stack_guard_data_.thread_local_.interrupt_flags_ |= TERMINATE; |
287 set_limits(kInterruptLimit, access); | 306 set_limits(kInterruptLimit, access); |
288 } | 307 } |
289 | 308 |
290 | 309 |
291 #ifdef ENABLE_DEBUGGER_SUPPORT | 310 #ifdef ENABLE_DEBUGGER_SUPPORT |
292 bool StackGuard::IsDebugBreak() { | 311 bool StackGuard::IsDebugBreak() { |
293 ExecutionAccess access; | 312 ExecutionAccess access; |
294 return thread_local_.interrupt_flags_ & DEBUGBREAK; | 313 return v8_context()-> |
| 314 stack_guard_data_.thread_local_.interrupt_flags_ & DEBUGBREAK; |
295 } | 315 } |
296 | 316 |
297 | 317 |
298 void StackGuard::DebugBreak() { | 318 void StackGuard::DebugBreak() { |
299 ExecutionAccess access; | 319 ExecutionAccess access; |
300 thread_local_.interrupt_flags_ |= DEBUGBREAK; | 320 v8_context()->stack_guard_data_.thread_local_.interrupt_flags_ |= DEBUGBREAK; |
301 set_limits(kInterruptLimit, access); | 321 set_limits(kInterruptLimit, access); |
302 } | 322 } |
303 | 323 |
304 | 324 |
305 bool StackGuard::IsDebugCommand() { | 325 bool StackGuard::IsDebugCommand() { |
306 ExecutionAccess access; | 326 ExecutionAccess access; |
307 return thread_local_.interrupt_flags_ & DEBUGCOMMAND; | 327 return v8_context()-> |
| 328 stack_guard_data_.thread_local_.interrupt_flags_ & DEBUGCOMMAND; |
308 } | 329 } |
309 | 330 |
310 | 331 |
311 void StackGuard::DebugCommand() { | 332 void StackGuard::DebugCommand() { |
312 if (FLAG_debugger_auto_break) { | 333 if (FLAG_debugger_auto_break) { |
313 ExecutionAccess access; | 334 ExecutionAccess access; |
314 thread_local_.interrupt_flags_ |= DEBUGCOMMAND; | 335 v8_context()-> |
| 336 stack_guard_data_.thread_local_.interrupt_flags_ |= DEBUGCOMMAND; |
315 set_limits(kInterruptLimit, access); | 337 set_limits(kInterruptLimit, access); |
316 } | 338 } |
317 } | 339 } |
318 #endif | 340 #endif |
319 | 341 |
320 void StackGuard::Continue(InterruptFlag after_what) { | 342 void StackGuard::Continue(InterruptFlag after_what) { |
321 ExecutionAccess access; | 343 ExecutionAccess access; |
322 thread_local_.interrupt_flags_ &= ~static_cast<int>(after_what); | 344 StackGuardData::ThreadLocal& thread_local = v8_context()-> |
323 if (thread_local_.interrupt_flags_ == 0) { | 345 stack_guard_data_.thread_local_; |
| 346 thread_local.interrupt_flags_ &= ~static_cast<int>(after_what); |
| 347 if (thread_local.interrupt_flags_ == 0) { |
324 reset_limits(access); | 348 reset_limits(access); |
325 } | 349 } |
326 } | 350 } |
327 | 351 |
328 | 352 |
329 int StackGuard::ArchiveSpacePerThread() { | 353 int StackGuard::ArchiveSpacePerThread() { |
330 return sizeof(ThreadLocal); | 354 return sizeof(StackGuardData::ThreadLocal); |
331 } | 355 } |
332 | 356 |
333 | 357 |
334 char* StackGuard::ArchiveStackGuard(char* to) { | 358 char* StackGuard::ArchiveStackGuard(char* to) { |
335 ExecutionAccess access; | 359 ExecutionAccess access; |
336 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal)); | 360 StackGuardData::ThreadLocal& thread_local = v8_context()-> |
337 ThreadLocal blank; | 361 stack_guard_data_.thread_local_; |
338 thread_local_ = blank; | 362 memcpy( |
339 return to + sizeof(ThreadLocal); | 363 to, |
| 364 reinterpret_cast<char*>(&thread_local), |
| 365 sizeof(StackGuardData::ThreadLocal)); |
| 366 StackGuardData::ThreadLocal blank; |
| 367 thread_local = blank; |
| 368 return to + sizeof(StackGuardData::ThreadLocal); |
340 } | 369 } |
341 | 370 |
342 | 371 |
343 char* StackGuard::RestoreStackGuard(char* from) { | 372 char* StackGuard::RestoreStackGuard(char* from) { |
344 ExecutionAccess access; | 373 ExecutionAccess access; |
345 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal)); | 374 memcpy( |
| 375 reinterpret_cast<char*>(&v8_context()->stack_guard_data_.thread_local_), |
| 376 from, |
| 377 sizeof(StackGuardData::ThreadLocal)); |
346 Heap::SetStackLimits(); | 378 Heap::SetStackLimits(); |
347 return from + sizeof(ThreadLocal); | 379 return from + sizeof(StackGuardData::ThreadLocal); |
348 } | 380 } |
349 | 381 |
350 | 382 |
351 static internal::Thread::LocalStorageKey stack_limit_key = | 383 void StackGuard::PostConstruct() { |
352 internal::Thread::CreateThreadLocalKey(); | 384 V8Context* const v8context = v8_context(); |
| 385 v8context->stack_guard_data_.thread_local_.Clear(); |
| 386 v8context->stack_guard_data_.stack_guard_private_data_ = |
| 387 new StackGuardPrivateData(); |
| 388 } |
353 | 389 |
| 390 void StackGuard::PreDestroy() { |
| 391 delete v8_context()->stack_guard_data_.stack_guard_private_data_; |
| 392 } |
354 | 393 |
355 void StackGuard::FreeThreadResources() { | 394 void StackGuard::FreeThreadResources() { |
| 395 StackGuardData& stack_guard_data = v8_context()->stack_guard_data_; |
356 Thread::SetThreadLocal( | 396 Thread::SetThreadLocal( |
357 stack_limit_key, | 397 stack_guard_data.stack_guard_private_data_->stack_limit_key, |
358 reinterpret_cast<void*>(thread_local_.real_climit_)); | 398 reinterpret_cast<void*>(stack_guard_data.thread_local_.real_climit_)); |
359 } | 399 } |
360 | 400 |
361 | 401 |
362 void StackGuard::ThreadLocal::Clear() { | 402 void StackGuardData::ThreadLocal::Clear() { |
363 real_jslimit_ = kIllegalLimit; | 403 real_jslimit_ = StackGuard::kIllegalLimit; |
364 jslimit_ = kIllegalLimit; | 404 jslimit_ = StackGuard::kIllegalLimit; |
365 real_climit_ = kIllegalLimit; | 405 real_climit_ = StackGuard::kIllegalLimit; |
366 climit_ = kIllegalLimit; | 406 climit_ = StackGuard::kIllegalLimit; |
367 nesting_ = 0; | 407 nesting_ = 0; |
368 postpone_interrupts_nesting_ = 0; | 408 postpone_interrupts_nesting_ = 0; |
369 interrupt_flags_ = 0; | 409 interrupt_flags_ = 0; |
370 Heap::SetStackLimits(); | 410 Heap::SetStackLimits(); |
371 } | 411 } |
372 | 412 |
373 | 413 |
374 void StackGuard::ThreadLocal::Initialize() { | 414 void StackGuardData::ThreadLocal::Initialize() { |
375 if (real_climit_ == kIllegalLimit) { | 415 if (real_climit_ == StackGuard::kIllegalLimit) { |
376 // Takes the address of the limit variable in order to find out where | 416 // Takes the address of the limit variable in order to find out where |
377 // the top of stack is right now. | 417 // the top of stack is right now. |
378 uintptr_t limit = reinterpret_cast<uintptr_t>(&limit) - kLimitSize; | 418 uintptr_t limit = reinterpret_cast<uintptr_t>(&limit) - |
379 ASSERT(reinterpret_cast<uintptr_t>(&limit) > kLimitSize); | 419 StackGuard::kLimitSize; |
| 420 ASSERT(reinterpret_cast<uintptr_t>(&limit) > StackGuard::kLimitSize); |
380 real_jslimit_ = SimulatorStack::JsLimitFromCLimit(limit); | 421 real_jslimit_ = SimulatorStack::JsLimitFromCLimit(limit); |
381 jslimit_ = SimulatorStack::JsLimitFromCLimit(limit); | 422 jslimit_ = SimulatorStack::JsLimitFromCLimit(limit); |
382 real_climit_ = limit; | 423 real_climit_ = limit; |
383 climit_ = limit; | 424 climit_ = limit; |
384 Heap::SetStackLimits(); | 425 Heap::SetStackLimits(); |
385 } | 426 } |
386 nesting_ = 0; | 427 nesting_ = 0; |
387 postpone_interrupts_nesting_ = 0; | 428 postpone_interrupts_nesting_ = 0; |
388 interrupt_flags_ = 0; | 429 interrupt_flags_ = 0; |
389 } | 430 } |
390 | 431 |
391 | 432 |
392 void StackGuard::ClearThread(const ExecutionAccess& lock) { | 433 void StackGuard::ClearThread(const ExecutionAccess& lock) { |
393 thread_local_.Clear(); | 434 v8_context()->stack_guard_data_.thread_local_.Clear(); |
394 } | 435 } |
395 | 436 |
396 | 437 |
397 void StackGuard::InitThread(const ExecutionAccess& lock) { | 438 void StackGuard::InitThread(const ExecutionAccess& lock) { |
398 thread_local_.Initialize(); | 439 StackGuardData& stack_guard_data = v8_context()->stack_guard_data_; |
399 void* stored_limit = Thread::GetThreadLocal(stack_limit_key); | 440 stack_guard_data.thread_local_.Initialize(); |
| 441 void* stored_limit = Thread::GetThreadLocal( |
| 442 stack_guard_data.stack_guard_private_data_->stack_limit_key); |
400 // You should hold the ExecutionAccess lock when you call this. | 443 // You should hold the ExecutionAccess lock when you call this. |
401 if (stored_limit != NULL) { | 444 if (stored_limit != NULL) { |
402 StackGuard::SetStackLimit(reinterpret_cast<intptr_t>(stored_limit)); | 445 StackGuard::SetStackLimit(reinterpret_cast<intptr_t>(stored_limit)); |
403 } | 446 } |
404 } | 447 } |
405 | 448 |
406 | 449 |
407 // --- C a l l s t o n a t i v e s --- | 450 // --- C a l l s t o n a t i v e s --- |
408 | 451 |
409 #define RETURN_NATIVE_CALL(name, argc, argv, has_pending_exception) \ | 452 #define RETURN_NATIVE_CALL(name, argc, argv, has_pending_exception) \ |
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
682 // All allocation spaces other than NEW_SPACE have the same effect. | 725 // All allocation spaces other than NEW_SPACE have the same effect. |
683 Heap::CollectAllGarbage(false); | 726 Heap::CollectAllGarbage(false); |
684 return v8::Undefined(); | 727 return v8::Undefined(); |
685 } | 728 } |
686 | 729 |
687 | 730 |
688 static GCExtension kGCExtension; | 731 static GCExtension kGCExtension; |
689 v8::DeclareExtension kGCExtensionDeclaration(&kGCExtension); | 732 v8::DeclareExtension kGCExtensionDeclaration(&kGCExtension); |
690 | 733 |
691 } } // namespace v8::internal | 734 } } // namespace v8::internal |
OLD | NEW |