Chromium Code Reviews| 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 22 matching lines...) Expand all Loading... | |
| 33 #include "bootstrapper.h" | 33 #include "bootstrapper.h" |
| 34 #include "codegen-inl.h" | 34 #include "codegen-inl.h" |
| 35 #include "debug.h" | 35 #include "debug.h" |
| 36 #include "simulator.h" | 36 #include "simulator.h" |
| 37 #include "v8threads.h" | 37 #include "v8threads.h" |
| 38 | 38 |
| 39 namespace v8 { | 39 namespace v8 { |
| 40 namespace internal { | 40 namespace internal { |
| 41 | 41 |
| 42 | 42 |
| 43 StackGuard::StackGuard() | |
| 44 : isolate_(NULL), | |
| 45 stack_limit_key_(Thread::CreateThreadLocalKey()) { | |
| 46 thread_local_.Clear(); | |
| 47 } | |
| 48 | |
| 49 | |
| 50 void StackGuard::set_interrupt_limits(const ExecutionAccess& lock) { | |
| 51 ASSERT(isolate_ != NULL); | |
| 52 // Ignore attempts to interrupt when interrupts are postponed. | |
| 53 if (should_postpone_interrupts(lock)) return; | |
| 54 thread_local_.jslimit_ = kInterruptLimit; | |
| 55 thread_local_.climit_ = kInterruptLimit; | |
| 56 isolate_->heap()->SetStackLimits(); | |
| 57 } | |
| 58 | |
| 59 | |
| 60 void StackGuard::reset_limits(const ExecutionAccess& lock) { | |
| 61 ASSERT(isolate_ != NULL); | |
| 62 thread_local_.jslimit_ = thread_local_.real_jslimit_; | |
| 63 thread_local_.climit_ = thread_local_.real_climit_; | |
| 64 isolate_->heap()->SetStackLimits(); | |
| 65 } | |
| 66 | |
| 67 | |
| 43 static Handle<Object> Invoke(bool construct, | 68 static Handle<Object> Invoke(bool construct, |
| 44 Handle<JSFunction> func, | 69 Handle<JSFunction> func, |
| 45 Handle<Object> receiver, | 70 Handle<Object> receiver, |
| 46 int argc, | 71 int argc, |
| 47 Object*** args, | 72 Object*** args, |
| 48 bool* has_pending_exception) { | 73 bool* has_pending_exception) { |
| 49 // Entering JavaScript. | 74 // Entering JavaScript. |
| 50 VMState state(JS); | 75 VMState state(JS); |
| 51 | 76 |
| 52 // Placeholder for return value. | 77 // Placeholder for return value. |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 198 if (object->IsHeapObject() && | 223 if (object->IsHeapObject() && |
| 199 HeapObject::cast(*object)->map()->has_instance_call_handler()) { | 224 HeapObject::cast(*object)->map()->has_instance_call_handler()) { |
| 200 return Handle<JSFunction>( | 225 return Handle<JSFunction>( |
| 201 Top::global_context()->call_as_constructor_delegate()); | 226 Top::global_context()->call_as_constructor_delegate()); |
| 202 } | 227 } |
| 203 | 228 |
| 204 return Factory::undefined_value(); | 229 return Factory::undefined_value(); |
| 205 } | 230 } |
| 206 | 231 |
| 207 | 232 |
| 208 // Static state for stack guards. | |
| 209 StackGuard::ThreadLocal StackGuard::thread_local_; | |
| 210 | |
| 211 | |
| 212 bool StackGuard::IsStackOverflow() { | 233 bool StackGuard::IsStackOverflow() { |
| 213 ExecutionAccess access; | 234 ExecutionAccess access; |
| 214 return (thread_local_.jslimit_ != kInterruptLimit && | 235 return (thread_local_.jslimit_ != kInterruptLimit && |
| 215 thread_local_.climit_ != kInterruptLimit); | 236 thread_local_.climit_ != kInterruptLimit); |
| 216 } | 237 } |
| 217 | 238 |
| 218 | 239 |
| 219 void StackGuard::EnableInterrupts() { | 240 void StackGuard::EnableInterrupts() { |
| 220 ExecutionAccess access; | 241 ExecutionAccess access; |
| 221 if (has_pending_interrupts(access)) { | 242 if (has_pending_interrupts(access)) { |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 316 | 337 |
| 317 void StackGuard::Continue(InterruptFlag after_what) { | 338 void StackGuard::Continue(InterruptFlag after_what) { |
| 318 ExecutionAccess access; | 339 ExecutionAccess access; |
| 319 thread_local_.interrupt_flags_ &= ~static_cast<int>(after_what); | 340 thread_local_.interrupt_flags_ &= ~static_cast<int>(after_what); |
| 320 if (!should_postpone_interrupts(access) && !has_pending_interrupts(access)) { | 341 if (!should_postpone_interrupts(access) && !has_pending_interrupts(access)) { |
| 321 reset_limits(access); | 342 reset_limits(access); |
| 322 } | 343 } |
| 323 } | 344 } |
| 324 | 345 |
| 325 | 346 |
| 326 int StackGuard::ArchiveSpacePerThread() { | |
| 327 return sizeof(ThreadLocal); | |
| 328 } | |
| 329 | |
| 330 | |
| 331 char* StackGuard::ArchiveStackGuard(char* to) { | 347 char* StackGuard::ArchiveStackGuard(char* to) { |
| 332 ExecutionAccess access; | 348 ExecutionAccess access; |
| 333 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal)); | 349 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal)); |
| 334 ThreadLocal blank; | 350 ThreadLocal blank; |
|
Vitaly Repeshko
2010/06/09 21:22:38
Can we make its constructor call Clear()?
| |
| 351 blank.Clear(); | |
| 352 | |
| 353 // Set the stack limits using the old thread_local_. | |
| 354 // TODO(isolates): This was the old semantics of constructing a ThreadLocal | |
| 355 // (as the ctor called SetStackLimits, which looked at the | |
| 356 // current thread_local_ from StackGuard)-- but is this | |
| 357 // really what was intended? | |
| 358 isolate_->heap()->SetStackLimits(); | |
| 359 | |
| 335 thread_local_ = blank; | 360 thread_local_ = blank; |
| 336 return to + sizeof(ThreadLocal); | 361 return to + sizeof(ThreadLocal); |
| 337 } | 362 } |
| 338 | 363 |
| 339 | 364 |
| 340 char* StackGuard::RestoreStackGuard(char* from) { | 365 char* StackGuard::RestoreStackGuard(char* from) { |
| 341 ExecutionAccess access; | 366 ExecutionAccess access; |
| 342 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal)); | 367 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal)); |
| 343 Heap::SetStackLimits(); | 368 isolate_->heap()->SetStackLimits(); |
| 344 return from + sizeof(ThreadLocal); | 369 return from + sizeof(ThreadLocal); |
| 345 } | 370 } |
| 346 | 371 |
| 347 | 372 |
| 348 static internal::Thread::LocalStorageKey stack_limit_key = | 373 static internal::Thread::LocalStorageKey stack_limit_key = |
| 349 internal::Thread::CreateThreadLocalKey(); | 374 internal::Thread::CreateThreadLocalKey(); |
| 350 | 375 |
| 351 | 376 |
| 352 void StackGuard::FreeThreadResources() { | 377 void StackGuard::FreeThreadResources() { |
| 353 Thread::SetThreadLocal( | 378 Thread::SetThreadLocal( |
| 354 stack_limit_key, | 379 stack_limit_key, |
| 355 reinterpret_cast<void*>(thread_local_.real_climit_)); | 380 reinterpret_cast<void*>(thread_local_.real_climit_)); |
| 356 } | 381 } |
| 357 | 382 |
| 358 | 383 |
| 384 StackGuard::ThreadLocal::ThreadLocal() { | |
| 385 } | |
| 386 | |
| 387 | |
| 359 void StackGuard::ThreadLocal::Clear() { | 388 void StackGuard::ThreadLocal::Clear() { |
| 360 real_jslimit_ = kIllegalLimit; | 389 real_jslimit_ = kIllegalLimit; |
| 361 jslimit_ = kIllegalLimit; | 390 jslimit_ = kIllegalLimit; |
| 362 real_climit_ = kIllegalLimit; | 391 real_climit_ = kIllegalLimit; |
| 363 climit_ = kIllegalLimit; | 392 climit_ = kIllegalLimit; |
| 364 nesting_ = 0; | 393 nesting_ = 0; |
| 365 postpone_interrupts_nesting_ = 0; | 394 postpone_interrupts_nesting_ = 0; |
| 366 interrupt_flags_ = 0; | 395 interrupt_flags_ = 0; |
| 367 Heap::SetStackLimits(); | |
| 368 } | 396 } |
| 369 | 397 |
| 370 | 398 |
| 371 void StackGuard::ThreadLocal::Initialize() { | 399 bool StackGuard::ThreadLocal::Initialize() { |
| 400 bool should_set_stack_limits = false; | |
| 372 if (real_climit_ == kIllegalLimit) { | 401 if (real_climit_ == kIllegalLimit) { |
| 373 // Takes the address of the limit variable in order to find out where | 402 // Takes the address of the limit variable in order to find out where |
| 374 // the top of stack is right now. | 403 // the top of stack is right now. |
| 375 uintptr_t limit = reinterpret_cast<uintptr_t>(&limit) - kLimitSize; | 404 uintptr_t limit = reinterpret_cast<uintptr_t>(&limit) - kLimitSize; |
| 376 ASSERT(reinterpret_cast<uintptr_t>(&limit) > kLimitSize); | 405 ASSERT(reinterpret_cast<uintptr_t>(&limit) > kLimitSize); |
| 377 real_jslimit_ = SimulatorStack::JsLimitFromCLimit(limit); | 406 real_jslimit_ = SimulatorStack::JsLimitFromCLimit(limit); |
| 378 jslimit_ = SimulatorStack::JsLimitFromCLimit(limit); | 407 jslimit_ = SimulatorStack::JsLimitFromCLimit(limit); |
| 379 real_climit_ = limit; | 408 real_climit_ = limit; |
| 380 climit_ = limit; | 409 climit_ = limit; |
| 381 Heap::SetStackLimits(); | 410 should_set_stack_limits = true; |
| 382 } | 411 } |
| 383 nesting_ = 0; | 412 nesting_ = 0; |
| 384 postpone_interrupts_nesting_ = 0; | 413 postpone_interrupts_nesting_ = 0; |
| 385 interrupt_flags_ = 0; | 414 interrupt_flags_ = 0; |
| 415 return should_set_stack_limits; | |
| 386 } | 416 } |
| 387 | 417 |
| 388 | 418 |
| 389 void StackGuard::ClearThread(const ExecutionAccess& lock) { | 419 void StackGuard::ClearThread(const ExecutionAccess& lock) { |
| 390 thread_local_.Clear(); | 420 thread_local_.Clear(); |
| 421 isolate_->heap()->SetStackLimits(); | |
| 391 } | 422 } |
| 392 | 423 |
| 393 | 424 |
| 394 void StackGuard::InitThread(const ExecutionAccess& lock) { | 425 void StackGuard::InitThread(const ExecutionAccess& lock) { |
| 395 thread_local_.Initialize(); | 426 if (thread_local_.Initialize()) { isolate_->heap()->SetStackLimits(); } |
|
Vitaly Repeshko
2010/06/09 21:22:38
nit: No {} for one-line ifs.
| |
| 396 void* stored_limit = Thread::GetThreadLocal(stack_limit_key); | 427 void* stored_limit = Thread::GetThreadLocal(stack_limit_key); |
| 397 // You should hold the ExecutionAccess lock when you call this. | 428 // You should hold the ExecutionAccess lock when you call this. |
| 398 if (stored_limit != NULL) { | 429 if (stored_limit != NULL) { |
| 399 StackGuard::SetStackLimit(reinterpret_cast<intptr_t>(stored_limit)); | 430 StackGuard::SetStackLimit(reinterpret_cast<intptr_t>(stored_limit)); |
| 400 } | 431 } |
| 401 } | 432 } |
| 402 | 433 |
| 403 | 434 |
| 404 // --- C a l l s t o n a t i v e s --- | 435 // --- C a l l s t o n a t i v e s --- |
| 405 | 436 |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 565 bool caught_exception = false; | 596 bool caught_exception = false; |
| 566 Handle<Object> result = TryCall(Top::get_stack_trace_line_fun(), | 597 Handle<Object> result = TryCall(Top::get_stack_trace_line_fun(), |
| 567 Top::builtins(), argc, args, | 598 Top::builtins(), argc, args, |
| 568 &caught_exception); | 599 &caught_exception); |
| 569 if (caught_exception || !result->IsString()) return Factory::empty_symbol(); | 600 if (caught_exception || !result->IsString()) return Factory::empty_symbol(); |
| 570 return Handle<String>::cast(result); | 601 return Handle<String>::cast(result); |
| 571 } | 602 } |
| 572 | 603 |
| 573 | 604 |
| 574 static Object* RuntimePreempt() { | 605 static Object* RuntimePreempt() { |
| 606 Isolate* isolate = Isolate::Current(); | |
| 607 | |
| 575 // Clear the preempt request flag. | 608 // Clear the preempt request flag. |
| 576 StackGuard::Continue(PREEMPT); | 609 isolate->stack_guard()->Continue(PREEMPT); |
| 577 | 610 |
| 578 ContextSwitcher::PreemptionReceived(); | 611 ContextSwitcher::PreemptionReceived(); |
| 579 | 612 |
| 580 #ifdef ENABLE_DEBUGGER_SUPPORT | 613 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 581 if (Debug::InDebugger()) { | 614 if (Debug::InDebugger()) { |
| 582 // If currently in the debugger don't do any actual preemption but record | 615 // If currently in the debugger don't do any actual preemption but record |
| 583 // that preemption occoured while in the debugger. | 616 // that preemption occoured while in the debugger. |
| 584 Debug::PreemptionWhileInDebugger(); | 617 Debug::PreemptionWhileInDebugger(); |
| 585 } else { | 618 } else { |
| 586 // Perform preemption. | 619 // Perform preemption. |
| 587 v8::Unlocker unlocker; | 620 v8::Unlocker unlocker; |
| 588 Thread::YieldCPU(); | 621 Thread::YieldCPU(); |
| 589 } | 622 } |
| 590 #else | 623 #else |
| 591 // Perform preemption. | 624 // Perform preemption. |
|
Vitaly Repeshko
2010/06/09 21:22:38
Unrelated to your change, but this looks like a ra
| |
| 592 v8::Unlocker unlocker; | 625 v8::Unlocker unlocker; |
| 593 Thread::YieldCPU(); | 626 Thread::YieldCPU(); |
| 594 #endif | 627 #endif |
| 595 | 628 |
| 596 return HEAP->undefined_value(); | 629 return isolate->heap()->undefined_value(); |
| 597 } | 630 } |
| 598 | 631 |
| 599 | 632 |
| 600 #ifdef ENABLE_DEBUGGER_SUPPORT | 633 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 601 Object* Execution::DebugBreakHelper() { | 634 Object* Execution::DebugBreakHelper() { |
| 635 Isolate* isolate = Isolate::Current(); | |
| 636 | |
| 602 // Just continue if breaks are disabled. | 637 // Just continue if breaks are disabled. |
| 603 if (Debug::disable_break()) { | 638 if (Debug::disable_break()) { |
| 604 return HEAP->undefined_value(); | 639 return isolate->heap()->undefined_value(); |
| 605 } | 640 } |
| 606 | 641 |
| 607 // Ignore debug break during bootstrapping. | 642 // Ignore debug break during bootstrapping. |
| 608 if (Bootstrapper::IsActive()) { | 643 if (Bootstrapper::IsActive()) { |
| 609 return HEAP->undefined_value(); | 644 return isolate->heap()->undefined_value(); |
| 610 } | 645 } |
| 611 | 646 |
| 612 { | 647 { |
| 613 JavaScriptFrameIterator it; | 648 JavaScriptFrameIterator it; |
| 614 ASSERT(!it.done()); | 649 ASSERT(!it.done()); |
| 615 Object* fun = it.frame()->function(); | 650 Object* fun = it.frame()->function(); |
| 616 if (fun && fun->IsJSFunction()) { | 651 if (fun && fun->IsJSFunction()) { |
| 617 // Don't stop in builtin functions. | 652 // Don't stop in builtin functions. |
| 618 if (JSFunction::cast(fun)->IsBuiltin()) { | 653 if (JSFunction::cast(fun)->IsBuiltin()) { |
| 619 return HEAP->undefined_value(); | 654 return isolate->heap()->undefined_value(); |
| 620 } | 655 } |
| 621 GlobalObject* global = JSFunction::cast(fun)->context()->global(); | 656 GlobalObject* global = JSFunction::cast(fun)->context()->global(); |
| 622 // Don't stop in debugger functions. | 657 // Don't stop in debugger functions. |
| 623 if (Debug::IsDebugGlobal(global)) { | 658 if (Debug::IsDebugGlobal(global)) { |
| 624 return HEAP->undefined_value(); | 659 return isolate->heap()->undefined_value(); |
| 625 } | 660 } |
| 626 } | 661 } |
| 627 } | 662 } |
| 628 | 663 |
| 629 // Collect the break state before clearing the flags. | 664 // Collect the break state before clearing the flags. |
| 630 bool debug_command_only = | 665 bool debug_command_only = |
| 631 StackGuard::IsDebugCommand() && !StackGuard::IsDebugBreak(); | 666 isolate->stack_guard()->IsDebugCommand() && |
| 667 !isolate->stack_guard()->IsDebugBreak(); | |
| 632 | 668 |
| 633 // Clear the debug break request flag. | 669 // Clear the debug break request flag. |
| 634 StackGuard::Continue(DEBUGBREAK); | 670 isolate->stack_guard()->Continue(DEBUGBREAK); |
| 635 | 671 |
| 636 ProcessDebugMesssages(debug_command_only); | 672 ProcessDebugMesssages(debug_command_only); |
| 637 | 673 |
| 638 // Return to continue execution. | 674 // Return to continue execution. |
| 639 return HEAP->undefined_value(); | 675 return isolate->heap()->undefined_value(); |
| 640 } | 676 } |
| 641 | 677 |
| 642 void Execution::ProcessDebugMesssages(bool debug_command_only) { | 678 void Execution::ProcessDebugMesssages(bool debug_command_only) { |
| 643 // Clear the debug command request flag. | 679 // Clear the debug command request flag. |
| 644 StackGuard::Continue(DEBUGCOMMAND); | 680 Isolate::Current()->stack_guard()->Continue(DEBUGCOMMAND); |
| 645 | 681 |
| 646 HandleScope scope; | 682 HandleScope scope; |
| 647 // Enter the debugger. Just continue if we fail to enter the debugger. | 683 // Enter the debugger. Just continue if we fail to enter the debugger. |
| 648 EnterDebugger debugger; | 684 EnterDebugger debugger; |
| 649 if (debugger.FailedToEnter()) { | 685 if (debugger.FailedToEnter()) { |
| 650 return; | 686 return; |
| 651 } | 687 } |
| 652 | 688 |
| 653 // Notify the debug event listeners. Indicate auto continue if the break was | 689 // Notify the debug event listeners. Indicate auto continue if the break was |
| 654 // a debug command break. | 690 // a debug command break. |
| 655 Debugger::OnDebugBreak(Factory::undefined_value(), debug_command_only); | 691 Debugger::OnDebugBreak(Factory::undefined_value(), debug_command_only); |
| 656 } | 692 } |
| 657 | 693 |
| 658 | 694 |
| 659 #endif | 695 #endif |
| 660 | 696 |
| 661 Object* Execution::HandleStackGuardInterrupt() { | 697 Object* Execution::HandleStackGuardInterrupt() { |
| 698 Isolate* isolate = Isolate::Current(); | |
| 662 #ifdef ENABLE_DEBUGGER_SUPPORT | 699 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 663 if (StackGuard::IsDebugBreak() || StackGuard::IsDebugCommand()) { | 700 if (isolate->stack_guard()->IsDebugBreak() || |
| 701 isolate->stack_guard()->IsDebugCommand()) { | |
| 664 DebugBreakHelper(); | 702 DebugBreakHelper(); |
| 665 } | 703 } |
| 666 #endif | 704 #endif |
| 667 if (StackGuard::IsPreempted()) RuntimePreempt(); | 705 if (isolate->stack_guard()->IsPreempted()) RuntimePreempt(); |
| 668 if (StackGuard::IsTerminateExecution()) { | 706 if (isolate->stack_guard()->IsTerminateExecution()) { |
| 669 StackGuard::Continue(TERMINATE); | 707 isolate->stack_guard()->Continue(TERMINATE); |
| 670 return Top::TerminateExecution(); | 708 return Top::TerminateExecution(); |
| 671 } | 709 } |
| 672 if (StackGuard::IsInterrupted()) { | 710 if (isolate->stack_guard()->IsInterrupted()) { |
| 673 // interrupt | 711 // interrupt |
| 674 StackGuard::Continue(INTERRUPT); | 712 isolate->stack_guard()->Continue(INTERRUPT); |
| 675 return Top::StackOverflow(); | 713 return Top::StackOverflow(); |
| 676 } | 714 } |
| 677 return HEAP->undefined_value(); | 715 return isolate->heap()->undefined_value(); |
| 678 } | 716 } |
| 679 | 717 |
| 680 // --- G C E x t e n s i o n --- | 718 // --- G C E x t e n s i o n --- |
| 681 | 719 |
| 682 const char* GCExtension::kSource = "native function gc();"; | 720 const char* GCExtension::kSource = "native function gc();"; |
| 683 | 721 |
| 684 | 722 |
| 685 v8::Handle<v8::FunctionTemplate> GCExtension::GetNativeFunction( | 723 v8::Handle<v8::FunctionTemplate> GCExtension::GetNativeFunction( |
| 686 v8::Handle<v8::String> str) { | 724 v8::Handle<v8::String> str) { |
| 687 return v8::FunctionTemplate::New(GCExtension::GC); | 725 return v8::FunctionTemplate::New(GCExtension::GC); |
| 688 } | 726 } |
| 689 | 727 |
| 690 | 728 |
| 691 v8::Handle<v8::Value> GCExtension::GC(const v8::Arguments& args) { | 729 v8::Handle<v8::Value> GCExtension::GC(const v8::Arguments& args) { |
| 692 // All allocation spaces other than NEW_SPACE have the same effect. | 730 // All allocation spaces other than NEW_SPACE have the same effect. |
| 693 Heap::CollectAllGarbage(false); | 731 Heap::CollectAllGarbage(false); |
| 694 return v8::Undefined(); | 732 return v8::Undefined(); |
| 695 } | 733 } |
| 696 | 734 |
| 697 | 735 |
| 698 static GCExtension kGCExtension; | 736 static GCExtension kGCExtension; |
| 699 v8::DeclareExtension kGCExtensionDeclaration(&kGCExtension); | 737 v8::DeclareExtension kGCExtensionDeclaration(&kGCExtension); |
| 700 | 738 |
| 701 } } // namespace v8::internal | 739 } } // namespace v8::internal |
| OLD | NEW |