| 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 |