OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 12 matching lines...) Loading... |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include <stdlib.h> | 28 #include <stdlib.h> |
29 | 29 |
30 #include "src/v8.h" | 30 #include "src/v8.h" |
31 | 31 |
32 #include "src/api.h" | 32 #include "src/api.h" |
33 #include "src/base/platform/condition-variable.h" | |
34 #include "src/base/platform/platform.h" | |
35 #include "src/compilation-cache.h" | 33 #include "src/compilation-cache.h" |
36 #include "src/debug/debug-interface.h" | 34 #include "src/debug/debug-interface.h" |
37 #include "src/debug/debug.h" | 35 #include "src/debug/debug.h" |
38 #include "src/deoptimizer.h" | 36 #include "src/deoptimizer.h" |
39 #include "src/frames.h" | 37 #include "src/frames.h" |
40 #include "src/utils.h" | 38 #include "src/utils.h" |
41 #include "test/cctest/cctest.h" | 39 #include "test/cctest/cctest.h" |
42 | 40 |
43 using ::v8::base::Mutex; | |
44 using ::v8::base::LockGuard; | |
45 using ::v8::base::ConditionVariable; | |
46 using ::v8::base::OS; | |
47 using ::v8::base::Semaphore; | |
48 using ::v8::internal::EmbeddedVector; | 41 using ::v8::internal::EmbeddedVector; |
49 using ::v8::internal::Object; | 42 using ::v8::internal::Object; |
50 using ::v8::internal::Handle; | 43 using ::v8::internal::Handle; |
51 using ::v8::internal::Heap; | 44 using ::v8::internal::Heap; |
52 using ::v8::internal::JSGlobalProxy; | 45 using ::v8::internal::JSGlobalProxy; |
53 using ::v8::internal::Code; | 46 using ::v8::internal::Code; |
54 using ::v8::internal::Debug; | 47 using ::v8::internal::Debug; |
55 using ::v8::internal::CommandMessage; | |
56 using ::v8::internal::CommandMessageQueue; | |
57 using ::v8::internal::StackFrame; | 48 using ::v8::internal::StackFrame; |
58 using ::v8::internal::StepAction; | 49 using ::v8::internal::StepAction; |
59 using ::v8::internal::StepIn; // From StepAction enum | 50 using ::v8::internal::StepIn; // From StepAction enum |
60 using ::v8::internal::StepNext; // From StepAction enum | 51 using ::v8::internal::StepNext; // From StepAction enum |
61 using ::v8::internal::StepOut; // From StepAction enum | 52 using ::v8::internal::StepOut; // From StepAction enum |
62 using ::v8::internal::Vector; | 53 using ::v8::internal::Vector; |
63 using ::v8::internal::StrLength; | 54 using ::v8::internal::StrLength; |
64 | 55 |
65 // Size of temp buffer for formatting small strings. | 56 // Size of temp buffer for formatting small strings. |
66 #define SMALL_STRING_BUFFER_SIZE 80 | 57 #define SMALL_STRING_BUFFER_SIZE 80 |
(...skipping 334 matching lines...) Loading... |
401 } | 392 } |
402 | 393 |
403 | 394 |
404 } // namespace internal | 395 } // namespace internal |
405 } // namespace v8 | 396 } // namespace v8 |
406 | 397 |
407 | 398 |
408 // Check that the debugger has been fully unloaded. | 399 // Check that the debugger has been fully unloaded. |
409 static void CheckDebuggerUnloaded(v8::Isolate* isolate, | 400 static void CheckDebuggerUnloaded(v8::Isolate* isolate, |
410 bool check_functions = false) { | 401 bool check_functions = false) { |
411 // Let debugger to unload itself synchronously | |
412 v8::Debug::ProcessDebugMessages(isolate); | |
413 | |
414 v8::internal::CheckDebuggerUnloaded(check_functions); | 402 v8::internal::CheckDebuggerUnloaded(check_functions); |
415 } | 403 } |
416 | 404 |
417 | 405 |
418 // --- D e b u g E v e n t H a n d l e r s | 406 // --- D e b u g E v e n t H a n d l e r s |
419 // --- | 407 // --- |
420 // --- The different tests uses a number of debug event handlers. | 408 // --- The different tests uses a number of debug event handlers. |
421 // --- | 409 // --- |
422 | 410 |
423 | 411 |
(...skipping 2061 matching lines...) Loading... |
2485 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked(); | 2473 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked(); |
2486 CHECK_EQ(1, debugEventCount); | 2474 CHECK_EQ(1, debugEventCount); |
2487 | 2475 |
2488 checkGlobalEvalFunction.Clear(); | 2476 checkGlobalEvalFunction.Clear(); |
2489 checkFrameEvalFunction.Clear(); | 2477 checkFrameEvalFunction.Clear(); |
2490 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); | 2478 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); |
2491 CheckDebuggerUnloaded(env->GetIsolate()); | 2479 CheckDebuggerUnloaded(env->GetIsolate()); |
2492 } | 2480 } |
2493 | 2481 |
2494 | 2482 |
2495 // Copies a C string to a 16-bit string. Does not check for buffer overflow. | |
2496 // Does not use the V8 engine to convert strings, so it can be used | |
2497 // in any thread. Returns the length of the string. | |
2498 int AsciiToUtf16(const char* input_buffer, uint16_t* output_buffer) { | |
2499 int i; | |
2500 for (i = 0; input_buffer[i] != '\0'; ++i) { | |
2501 // ASCII does not use chars > 127, but be careful anyway. | |
2502 output_buffer[i] = static_cast<unsigned char>(input_buffer[i]); | |
2503 } | |
2504 output_buffer[i] = 0; | |
2505 return i; | |
2506 } | |
2507 | |
2508 | |
2509 // Copies a 16-bit string to a C string by dropping the high byte of | |
2510 // each character. Does not check for buffer overflow. | |
2511 // Can be used in any thread. Requires string length as an input. | |
2512 int Utf16ToAscii(const uint16_t* input_buffer, int length, | |
2513 char* output_buffer, int output_len = -1) { | |
2514 if (output_len >= 0) { | |
2515 if (length > output_len - 1) { | |
2516 length = output_len - 1; | |
2517 } | |
2518 } | |
2519 | |
2520 for (int i = 0; i < length; ++i) { | |
2521 output_buffer[i] = static_cast<char>(input_buffer[i]); | |
2522 } | |
2523 output_buffer[length] = '\0'; | |
2524 return length; | |
2525 } | |
2526 | |
2527 | |
2528 // We match parts of the message to get evaluate result int value. | |
2529 bool GetEvaluateStringResult(char *message, char* buffer, int buffer_size) { | |
2530 if (strstr(message, "\"command\":\"evaluate\"") == NULL) { | |
2531 return false; | |
2532 } | |
2533 const char* prefix = "\"text\":\""; | |
2534 char* pos1 = strstr(message, prefix); | |
2535 if (pos1 == NULL) { | |
2536 return false; | |
2537 } | |
2538 pos1 += strlen(prefix); | |
2539 char* pos2 = strchr(pos1, '"'); | |
2540 if (pos2 == NULL) { | |
2541 return false; | |
2542 } | |
2543 Vector<char> buf(buffer, buffer_size); | |
2544 int len = static_cast<int>(pos2 - pos1); | |
2545 if (len > buffer_size - 1) { | |
2546 len = buffer_size - 1; | |
2547 } | |
2548 StrNCpy(buf, pos1, len); | |
2549 buffer[buffer_size - 1] = '\0'; | |
2550 return true; | |
2551 } | |
2552 | |
2553 | |
2554 struct EvaluateResult { | |
2555 static const int kBufferSize = 20; | |
2556 char buffer[kBufferSize]; | |
2557 }; | |
2558 | |
2559 struct DebugProcessDebugMessagesData { | |
2560 static const int kArraySize = 5; | |
2561 int counter; | |
2562 EvaluateResult results[kArraySize]; | |
2563 | |
2564 void reset() { | |
2565 counter = 0; | |
2566 } | |
2567 EvaluateResult* current() { | |
2568 return &results[counter % kArraySize]; | |
2569 } | |
2570 void next() { | |
2571 counter++; | |
2572 } | |
2573 }; | |
2574 | |
2575 DebugProcessDebugMessagesData process_debug_messages_data; | |
2576 | |
2577 static void DebugProcessDebugMessagesHandler( | |
2578 const v8::Debug::Message& message) { | |
2579 v8::Local<v8::String> json = message.GetJSON(); | |
2580 v8::String::Utf8Value utf8(json); | |
2581 EvaluateResult* array_item = process_debug_messages_data.current(); | |
2582 | |
2583 bool res = GetEvaluateStringResult(*utf8, | |
2584 array_item->buffer, | |
2585 EvaluateResult::kBufferSize); | |
2586 if (res) { | |
2587 process_debug_messages_data.next(); | |
2588 } | |
2589 } | |
2590 | |
2591 | |
2592 // Test that the evaluation of expressions works even from ProcessDebugMessages | |
2593 // i.e. with empty stack. | |
2594 TEST(DebugEvaluateWithoutStack) { | |
2595 DebugLocalContext env; | |
2596 v8::Debug::SetMessageHandler(env->GetIsolate(), | |
2597 DebugProcessDebugMessagesHandler); | |
2598 v8::HandleScope scope(env->GetIsolate()); | |
2599 | |
2600 const char* source = | |
2601 "var v1 = 'Pinguin';\n function getAnimal() { return 'Capy' + 'bara'; }"; | |
2602 | |
2603 v8::Local<v8::Context> context = env.context(); | |
2604 v8::Script::Compile(context, v8_str(env->GetIsolate(), source)) | |
2605 .ToLocalChecked() | |
2606 ->Run(context) | |
2607 .ToLocalChecked(); | |
2608 | |
2609 v8::Debug::ProcessDebugMessages(env->GetIsolate()); | |
2610 | |
2611 const int kBufferSize = 1000; | |
2612 uint16_t buffer[kBufferSize]; | |
2613 | |
2614 const char* command_111 = "{\"seq\":111," | |
2615 "\"type\":\"request\"," | |
2616 "\"command\":\"evaluate\"," | |
2617 "\"arguments\":{" | |
2618 " \"global\":true," | |
2619 " \"expression\":\"v1\",\"disable_break\":true" | |
2620 "}}"; | |
2621 | |
2622 v8::Isolate* isolate = CcTest::isolate(); | |
2623 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_111, buffer)); | |
2624 | |
2625 const char* command_112 = "{\"seq\":112," | |
2626 "\"type\":\"request\"," | |
2627 "\"command\":\"evaluate\"," | |
2628 "\"arguments\":{" | |
2629 " \"global\":true," | |
2630 " \"expression\":\"getAnimal()\",\"disable_break\":true" | |
2631 "}}"; | |
2632 | |
2633 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_112, buffer)); | |
2634 | |
2635 const char* command_113 = "{\"seq\":113," | |
2636 "\"type\":\"request\"," | |
2637 "\"command\":\"evaluate\"," | |
2638 "\"arguments\":{" | |
2639 " \"global\":true," | |
2640 " \"expression\":\"239 + 566\",\"disable_break\":true" | |
2641 "}}"; | |
2642 | |
2643 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_113, buffer)); | |
2644 | |
2645 v8::Debug::ProcessDebugMessages(isolate); | |
2646 | |
2647 CHECK_EQ(3, process_debug_messages_data.counter); | |
2648 | |
2649 CHECK_EQ(strcmp("Pinguin", process_debug_messages_data.results[0].buffer), 0); | |
2650 CHECK_EQ(strcmp("Capybara", process_debug_messages_data.results[1].buffer), | |
2651 0); | |
2652 CHECK_EQ(strcmp("805", process_debug_messages_data.results[2].buffer), 0); | |
2653 | |
2654 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); | |
2655 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); | |
2656 CheckDebuggerUnloaded(env->GetIsolate()); | |
2657 } | |
2658 | |
2659 | |
2660 // Simple test of the stepping mechanism using only store ICs. | 2483 // Simple test of the stepping mechanism using only store ICs. |
2661 TEST(DebugStepLinear) { | 2484 TEST(DebugStepLinear) { |
2662 DebugLocalContext env; | 2485 DebugLocalContext env; |
2663 v8::HandleScope scope(env->GetIsolate()); | 2486 v8::HandleScope scope(env->GetIsolate()); |
2664 | 2487 |
2665 // Create a function for testing stepping. | 2488 // Create a function for testing stepping. |
2666 v8::Local<v8::Function> foo = CompileFunction(&env, | 2489 v8::Local<v8::Function> foo = CompileFunction(&env, |
2667 "function foo(){a=1;b=1;c=1;}", | 2490 "function foo(){a=1;b=1;c=1;}", |
2668 "foo"); | 2491 "foo"); |
2669 | 2492 |
(...skipping 2265 matching lines...) Loading... |
4935 .FromJust()); | 4758 .FromJust()); |
4936 CHECK(CompileRun("obj_mirror.property('a').value().value() == 1") | 4759 CHECK(CompileRun("obj_mirror.property('a').value().value() == 1") |
4937 ->BooleanValue(context) | 4760 ->BooleanValue(context) |
4938 .FromJust()); | 4761 .FromJust()); |
4939 CHECK(CompileRun("obj_mirror.property('b').value().value() == 2") | 4762 CHECK(CompileRun("obj_mirror.property('b').value().value() == 2") |
4940 ->BooleanValue(context) | 4763 ->BooleanValue(context) |
4941 .FromJust()); | 4764 .FromJust()); |
4942 } | 4765 } |
4943 | 4766 |
4944 | 4767 |
4945 // Multithreaded tests of JSON debugger protocol | |
4946 | |
4947 // Support classes | |
4948 | |
4949 // Provides synchronization between N threads, where N is a template parameter. | |
4950 // The Wait() call blocks a thread until it is called for the Nth time, then all | |
4951 // calls return. Each ThreadBarrier object can only be used once. | |
4952 template <int N> | |
4953 class ThreadBarrier final { | |
4954 public: | |
4955 ThreadBarrier() : num_blocked_(0) {} | |
4956 | |
4957 ~ThreadBarrier() { | |
4958 LockGuard<Mutex> lock_guard(&mutex_); | |
4959 if (num_blocked_ != 0) { | |
4960 CHECK_EQ(N, num_blocked_); | |
4961 } | |
4962 } | |
4963 | |
4964 void Wait() { | |
4965 LockGuard<Mutex> lock_guard(&mutex_); | |
4966 CHECK_LT(num_blocked_, N); | |
4967 num_blocked_++; | |
4968 if (N == num_blocked_) { | |
4969 // Signal and unblock all waiting threads. | |
4970 cv_.NotifyAll(); | |
4971 printf("BARRIER\n\n"); | |
4972 fflush(stdout); | |
4973 } else { // Wait for the semaphore. | |
4974 while (num_blocked_ < N) { | |
4975 cv_.Wait(&mutex_); | |
4976 } | |
4977 } | |
4978 CHECK_EQ(N, num_blocked_); | |
4979 } | |
4980 | |
4981 private: | |
4982 ConditionVariable cv_; | |
4983 Mutex mutex_; | |
4984 int num_blocked_; | |
4985 | |
4986 STATIC_ASSERT(N > 0); | |
4987 | |
4988 DISALLOW_COPY_AND_ASSIGN(ThreadBarrier); | |
4989 }; | |
4990 | |
4991 | |
4992 // A set containing enough barriers and semaphores for any of the tests. | |
4993 class Barriers { | |
4994 public: | |
4995 Barriers() : semaphore_1(0), semaphore_2(0) {} | |
4996 ThreadBarrier<2> barrier_1; | |
4997 ThreadBarrier<2> barrier_2; | |
4998 ThreadBarrier<2> barrier_3; | |
4999 ThreadBarrier<2> barrier_4; | |
5000 ThreadBarrier<2> barrier_5; | |
5001 v8::base::Semaphore semaphore_1; | |
5002 v8::base::Semaphore semaphore_2; | |
5003 }; | |
5004 | |
5005 | |
5006 // We match parts of the message to decide if it is a break message. | |
5007 bool IsBreakEventMessage(char *message) { | |
5008 const char* type_event = "\"type\":\"event\""; | |
5009 const char* event_break = "\"event\":\"break\""; | |
5010 // Does the message contain both type:event and event:break? | |
5011 return strstr(message, type_event) != NULL && | |
5012 strstr(message, event_break) != NULL; | |
5013 } | |
5014 | |
5015 | |
5016 // We match parts of the message to decide if it is a exception message. | |
5017 bool IsExceptionEventMessage(char *message) { | |
5018 const char* type_event = "\"type\":\"event\""; | |
5019 const char* event_exception = "\"event\":\"exception\""; | |
5020 // Does the message contain both type:event and event:exception? | |
5021 return strstr(message, type_event) != NULL && | |
5022 strstr(message, event_exception) != NULL; | |
5023 } | |
5024 | |
5025 | |
5026 // We match the message wether it is an evaluate response message. | |
5027 bool IsEvaluateResponseMessage(char* message) { | |
5028 const char* type_response = "\"type\":\"response\""; | |
5029 const char* command_evaluate = "\"command\":\"evaluate\""; | |
5030 // Does the message contain both type:response and command:evaluate? | |
5031 return strstr(message, type_response) != NULL && | |
5032 strstr(message, command_evaluate) != NULL; | |
5033 } | |
5034 | |
5035 | |
5036 static int StringToInt(const char* s) { | |
5037 return atoi(s); // NOLINT | |
5038 } | |
5039 | |
5040 | |
5041 // We match parts of the message to get evaluate result int value. | |
5042 int GetEvaluateIntResult(char *message) { | |
5043 const char* value = "\"value\":"; | |
5044 char* pos = strstr(message, value); | |
5045 if (pos == NULL) { | |
5046 return -1; | |
5047 } | |
5048 int res = -1; | |
5049 res = StringToInt(pos + strlen(value)); | |
5050 return res; | |
5051 } | |
5052 | |
5053 | |
5054 // We match parts of the message to get hit breakpoint id. | |
5055 int GetBreakpointIdFromBreakEventMessage(char *message) { | |
5056 const char* breakpoints = "\"breakpoints\":["; | |
5057 char* pos = strstr(message, breakpoints); | |
5058 if (pos == NULL) { | |
5059 return -1; | |
5060 } | |
5061 int res = -1; | |
5062 res = StringToInt(pos + strlen(breakpoints)); | |
5063 return res; | |
5064 } | |
5065 | |
5066 | |
5067 // We match parts of the message to get total frames number. | |
5068 int GetTotalFramesInt(char *message) { | |
5069 const char* prefix = "\"totalFrames\":"; | |
5070 char* pos = strstr(message, prefix); | |
5071 if (pos == NULL) { | |
5072 return -1; | |
5073 } | |
5074 pos += strlen(prefix); | |
5075 int res = StringToInt(pos); | |
5076 return res; | |
5077 } | |
5078 | |
5079 | |
5080 // We match parts of the message to get source line. | |
5081 int GetSourceLineFromBreakEventMessage(char *message) { | |
5082 const char* source_line = "\"sourceLine\":"; | |
5083 char* pos = strstr(message, source_line); | |
5084 if (pos == NULL) { | |
5085 return -1; | |
5086 } | |
5087 int res = -1; | |
5088 res = StringToInt(pos + strlen(source_line)); | |
5089 return res; | |
5090 } | |
5091 | |
5092 | |
5093 /* Test MessageQueues */ | |
5094 /* Tests the message queues that hold debugger commands and | |
5095 * response messages to the debugger. Fills queues and makes | |
5096 * them grow. | |
5097 */ | |
5098 Barriers message_queue_barriers; | |
5099 | |
5100 // This is the debugger thread, that executes no v8 calls except | |
5101 // placing JSON debugger commands in the queue. | |
5102 class MessageQueueDebuggerThread : public v8::base::Thread { | |
5103 public: | |
5104 MessageQueueDebuggerThread() | |
5105 : Thread(Options("MessageQueueDebuggerThread")) {} | |
5106 void Run(); | |
5107 }; | |
5108 | |
5109 | |
5110 static void MessageHandler(const v8::Debug::Message& message) { | |
5111 v8::Local<v8::String> json = message.GetJSON(); | |
5112 v8::String::Utf8Value utf8(json); | |
5113 if (IsBreakEventMessage(*utf8)) { | |
5114 // Lets test script wait until break occurs to send commands. | |
5115 // Signals when a break is reported. | |
5116 message_queue_barriers.semaphore_2.Signal(); | |
5117 } | |
5118 | |
5119 // Allow message handler to block on a semaphore, to test queueing of | |
5120 // messages while blocked. | |
5121 message_queue_barriers.semaphore_1.Wait(); | |
5122 } | |
5123 | |
5124 | |
5125 void MessageQueueDebuggerThread::Run() { | |
5126 const int kBufferSize = 1000; | |
5127 uint16_t buffer_1[kBufferSize]; | |
5128 uint16_t buffer_2[kBufferSize]; | |
5129 const char* command_1 = | |
5130 "{\"seq\":117," | |
5131 "\"type\":\"request\"," | |
5132 "\"command\":\"evaluate\"," | |
5133 "\"arguments\":{\"expression\":\"1+2\"}}"; | |
5134 const char* command_2 = | |
5135 "{\"seq\":118," | |
5136 "\"type\":\"request\"," | |
5137 "\"command\":\"evaluate\"," | |
5138 "\"arguments\":{\"expression\":\"1+a\"}}"; | |
5139 const char* command_3 = | |
5140 "{\"seq\":119," | |
5141 "\"type\":\"request\"," | |
5142 "\"command\":\"evaluate\"," | |
5143 "\"arguments\":{\"expression\":\"c.d * b\"}}"; | |
5144 const char* command_continue = | |
5145 "{\"seq\":106," | |
5146 "\"type\":\"request\"," | |
5147 "\"command\":\"continue\"}"; | |
5148 const char* command_single_step = | |
5149 "{\"seq\":107," | |
5150 "\"type\":\"request\"," | |
5151 "\"command\":\"continue\"," | |
5152 "\"arguments\":{\"stepaction\":\"next\"}}"; | |
5153 | |
5154 /* Interleaved sequence of actions by the two threads:*/ | |
5155 // Main thread compiles and runs source_1 | |
5156 message_queue_barriers.semaphore_1.Signal(); | |
5157 message_queue_barriers.barrier_1.Wait(); | |
5158 // Post 6 commands, filling the command queue and making it expand. | |
5159 // These calls return immediately, but the commands stay on the queue | |
5160 // until the execution of source_2. | |
5161 // Note: AsciiToUtf16 executes before SendCommand, so command is copied | |
5162 // to buffer before buffer is sent to SendCommand. | |
5163 v8::Isolate* isolate = CcTest::isolate(); | |
5164 v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_1, buffer_1)); | |
5165 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_2, buffer_2)); | |
5166 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2)); | |
5167 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2)); | |
5168 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2)); | |
5169 message_queue_barriers.barrier_2.Wait(); | |
5170 // Main thread compiles and runs source_2. | |
5171 // Queued commands are executed at the start of compilation of source_2( | |
5172 // beforeCompile event). | |
5173 // Free the message handler to process all the messages from the queue. 7 | |
5174 // messages are expected: 2 afterCompile events and 5 responses. | |
5175 // All the commands added so far will fail to execute as long as call stack | |
5176 // is empty on beforeCompile event. | |
5177 for (int i = 0; i < 6 ; ++i) { | |
5178 message_queue_barriers.semaphore_1.Signal(); | |
5179 } | |
5180 message_queue_barriers.barrier_3.Wait(); | |
5181 // Main thread compiles and runs source_3. | |
5182 // Don't stop in the afterCompile handler. | |
5183 message_queue_barriers.semaphore_1.Signal(); | |
5184 // source_3 includes a debugger statement, which causes a break event. | |
5185 // Wait on break event from hitting "debugger" statement | |
5186 message_queue_barriers.semaphore_2.Wait(); | |
5187 // These should execute after the "debugger" statement in source_2 | |
5188 v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_1, buffer_1)); | |
5189 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_2, buffer_2)); | |
5190 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2)); | |
5191 v8::Debug::SendCommand( | |
5192 isolate, buffer_2, AsciiToUtf16(command_single_step, buffer_2)); | |
5193 // Run after 2 break events, 4 responses. | |
5194 for (int i = 0; i < 6 ; ++i) { | |
5195 message_queue_barriers.semaphore_1.Signal(); | |
5196 } | |
5197 // Wait on break event after a single step executes. | |
5198 message_queue_barriers.semaphore_2.Wait(); | |
5199 v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_2, buffer_1)); | |
5200 v8::Debug::SendCommand( | |
5201 isolate, buffer_2, AsciiToUtf16(command_continue, buffer_2)); | |
5202 // Run after 2 responses. | |
5203 for (int i = 0; i < 2 ; ++i) { | |
5204 message_queue_barriers.semaphore_1.Signal(); | |
5205 } | |
5206 // Main thread continues running source_3 to end, waits for this thread. | |
5207 } | |
5208 | |
5209 | |
5210 // This thread runs the v8 engine. | |
5211 TEST(MessageQueues) { | |
5212 MessageQueueDebuggerThread message_queue_debugger_thread; | |
5213 | |
5214 // Create a V8 environment | |
5215 DebugLocalContext env; | |
5216 v8::HandleScope scope(env->GetIsolate()); | |
5217 v8::Debug::SetMessageHandler(env->GetIsolate(), MessageHandler); | |
5218 message_queue_debugger_thread.Start(); | |
5219 | |
5220 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;"; | |
5221 const char* source_2 = "e = 17;"; | |
5222 const char* source_3 = "a = 4; debugger; a = 5; a = 6; a = 7;"; | |
5223 | |
5224 // See MessageQueueDebuggerThread::Run for interleaved sequence of | |
5225 // API calls and events in the two threads. | |
5226 CompileRun(source_1); | |
5227 message_queue_barriers.barrier_1.Wait(); | |
5228 message_queue_barriers.barrier_2.Wait(); | |
5229 CompileRun(source_2); | |
5230 message_queue_barriers.barrier_3.Wait(); | |
5231 CompileRun(source_3); | |
5232 message_queue_debugger_thread.Join(); | |
5233 fflush(stdout); | |
5234 } | |
5235 | |
5236 | |
5237 class TestClientData : public v8::Debug::ClientData { | |
5238 public: | |
5239 TestClientData() { | |
5240 constructor_call_counter++; | |
5241 } | |
5242 virtual ~TestClientData() { | |
5243 destructor_call_counter++; | |
5244 } | |
5245 | |
5246 static void ResetCounters() { | |
5247 constructor_call_counter = 0; | |
5248 destructor_call_counter = 0; | |
5249 } | |
5250 | |
5251 static int constructor_call_counter; | |
5252 static int destructor_call_counter; | |
5253 }; | |
5254 | |
5255 int TestClientData::constructor_call_counter = 0; | |
5256 int TestClientData::destructor_call_counter = 0; | |
5257 | |
5258 | |
5259 // Tests that MessageQueue doesn't destroy client data when expands and | |
5260 // does destroy when it dies. | |
5261 TEST(MessageQueueExpandAndDestroy) { | |
5262 TestClientData::ResetCounters(); | |
5263 { // Create a scope for the queue. | |
5264 CommandMessageQueue queue(1); | |
5265 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), | |
5266 new TestClientData())); | |
5267 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), | |
5268 new TestClientData())); | |
5269 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), | |
5270 new TestClientData())); | |
5271 CHECK_EQ(0, TestClientData::destructor_call_counter); | |
5272 queue.Get().Dispose(); | |
5273 CHECK_EQ(1, TestClientData::destructor_call_counter); | |
5274 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), | |
5275 new TestClientData())); | |
5276 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), | |
5277 new TestClientData())); | |
5278 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), | |
5279 new TestClientData())); | |
5280 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), | |
5281 new TestClientData())); | |
5282 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(), | |
5283 new TestClientData())); | |
5284 CHECK_EQ(1, TestClientData::destructor_call_counter); | |
5285 queue.Get().Dispose(); | |
5286 CHECK_EQ(2, TestClientData::destructor_call_counter); | |
5287 } | |
5288 // All the client data should be destroyed when the queue is destroyed. | |
5289 CHECK_EQ(TestClientData::destructor_call_counter, | |
5290 TestClientData::destructor_call_counter); | |
5291 } | |
5292 | |
5293 | |
5294 static int handled_client_data_instances_count = 0; | |
5295 static void MessageHandlerCountingClientData( | |
5296 const v8::Debug::Message& message) { | |
5297 if (message.GetClientData() != NULL) { | |
5298 handled_client_data_instances_count++; | |
5299 } | |
5300 } | |
5301 | |
5302 | |
5303 // Tests that all client data passed to the debugger are sent to the handler. | |
5304 TEST(SendClientDataToHandler) { | |
5305 // Create a V8 environment | |
5306 DebugLocalContext env; | |
5307 v8::Isolate* isolate = env->GetIsolate(); | |
5308 v8::HandleScope scope(isolate); | |
5309 TestClientData::ResetCounters(); | |
5310 handled_client_data_instances_count = 0; | |
5311 v8::Debug::SetMessageHandler(isolate, MessageHandlerCountingClientData); | |
5312 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;"; | |
5313 const int kBufferSize = 1000; | |
5314 uint16_t buffer[kBufferSize]; | |
5315 const char* command_1 = | |
5316 "{\"seq\":117," | |
5317 "\"type\":\"request\"," | |
5318 "\"command\":\"evaluate\"," | |
5319 "\"arguments\":{\"expression\":\"1+2\"}}"; | |
5320 const char* command_2 = | |
5321 "{\"seq\":118," | |
5322 "\"type\":\"request\"," | |
5323 "\"command\":\"evaluate\"," | |
5324 "\"arguments\":{\"expression\":\"1+a\"}}"; | |
5325 const char* command_continue = | |
5326 "{\"seq\":106," | |
5327 "\"type\":\"request\"," | |
5328 "\"command\":\"continue\"}"; | |
5329 | |
5330 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_1, buffer), | |
5331 new TestClientData()); | |
5332 v8::Debug::SendCommand( | |
5333 isolate, buffer, AsciiToUtf16(command_2, buffer), NULL); | |
5334 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_2, buffer), | |
5335 new TestClientData()); | |
5336 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_2, buffer), | |
5337 new TestClientData()); | |
5338 // All the messages will be processed on beforeCompile event. | |
5339 CompileRun(source_1); | |
5340 v8::Debug::SendCommand( | |
5341 isolate, buffer, AsciiToUtf16(command_continue, buffer)); | |
5342 CHECK_EQ(3, TestClientData::constructor_call_counter); | |
5343 CHECK_EQ(TestClientData::constructor_call_counter, | |
5344 handled_client_data_instances_count); | |
5345 CHECK_EQ(TestClientData::constructor_call_counter, | |
5346 TestClientData::destructor_call_counter); | |
5347 } | |
5348 | |
5349 | |
5350 /* Test ThreadedDebugging */ | |
5351 /* This test interrupts a running infinite loop that is | |
5352 * occupying the v8 thread by a break command from the | |
5353 * debugger thread. It then changes the value of a | |
5354 * global object, to make the loop terminate. | |
5355 */ | |
5356 | |
5357 Barriers threaded_debugging_barriers; | |
5358 | |
5359 class V8Thread : public v8::base::Thread { | |
5360 public: | |
5361 V8Thread() : Thread(Options("V8Thread")) {} | |
5362 void Run(); | |
5363 v8::Isolate* isolate() { return isolate_; } | |
5364 | |
5365 private: | |
5366 v8::Isolate* isolate_; | |
5367 }; | |
5368 | |
5369 class DebuggerThread : public v8::base::Thread { | |
5370 public: | |
5371 explicit DebuggerThread(v8::Isolate* isolate) | |
5372 : Thread(Options("DebuggerThread")), isolate_(isolate) {} | |
5373 void Run(); | |
5374 | |
5375 private: | |
5376 v8::Isolate* isolate_; | |
5377 }; | |
5378 | |
5379 | |
5380 static void ThreadedAtBarrier1( | |
5381 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
5382 threaded_debugging_barriers.barrier_1.Wait(); | |
5383 } | |
5384 | |
5385 | |
5386 static void ThreadedMessageHandler(const v8::Debug::Message& message) { | |
5387 static char print_buffer[1000]; | |
5388 v8::String::Value json(message.GetJSON()); | |
5389 Utf16ToAscii(*json, json.length(), print_buffer); | |
5390 if (IsBreakEventMessage(print_buffer)) { | |
5391 // Check that we are inside the while loop. | |
5392 int source_line = GetSourceLineFromBreakEventMessage(print_buffer); | |
5393 CHECK(4 <= source_line && source_line <= 10); | |
5394 threaded_debugging_barriers.barrier_2.Wait(); | |
5395 } | |
5396 } | |
5397 | |
5398 | |
5399 void V8Thread::Run() { | |
5400 const char* source = | |
5401 "flag = true;\n" | |
5402 "\n" | |
5403 "function foo() {\n" | |
5404 " var x = 1;\n" | |
5405 " while ( flag == true ) {\n" | |
5406 " if ( x == 1 ) {\n" | |
5407 " ThreadedAtBarrier1();\n" | |
5408 " }\n" | |
5409 " x = x + 1;\n" | |
5410 " }\n" | |
5411 "}\n" | |
5412 "\n" | |
5413 "foo();\n"; | |
5414 | |
5415 v8::Isolate::CreateParams create_params; | |
5416 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); | |
5417 isolate_ = v8::Isolate::New(create_params); | |
5418 threaded_debugging_barriers.barrier_3.Wait(); | |
5419 { | |
5420 v8::Isolate::Scope isolate_scope(isolate_); | |
5421 DebugLocalContext env(isolate_); | |
5422 v8::HandleScope scope(isolate_); | |
5423 v8::Debug::SetMessageHandler(isolate_, &ThreadedMessageHandler); | |
5424 v8::Local<v8::ObjectTemplate> global_template = | |
5425 v8::ObjectTemplate::New(env->GetIsolate()); | |
5426 global_template->Set( | |
5427 v8_str(env->GetIsolate(), "ThreadedAtBarrier1"), | |
5428 v8::FunctionTemplate::New(isolate_, ThreadedAtBarrier1)); | |
5429 v8::Local<v8::Context> context = | |
5430 v8::Context::New(isolate_, NULL, global_template); | |
5431 v8::Context::Scope context_scope(context); | |
5432 | |
5433 CompileRun(source); | |
5434 } | |
5435 threaded_debugging_barriers.barrier_4.Wait(); | |
5436 isolate_->Dispose(); | |
5437 } | |
5438 | |
5439 | |
5440 void DebuggerThread::Run() { | |
5441 const int kBufSize = 1000; | |
5442 uint16_t buffer[kBufSize]; | |
5443 | |
5444 const char* command_1 = | |
5445 "{\"seq\":102," | |
5446 "\"type\":\"request\"," | |
5447 "\"command\":\"evaluate\"," | |
5448 "\"arguments\":{\"expression\":\"flag = false\"}}"; | |
5449 const char* command_2 = "{\"seq\":103," | |
5450 "\"type\":\"request\"," | |
5451 "\"command\":\"continue\"}"; | |
5452 | |
5453 threaded_debugging_barriers.barrier_1.Wait(); | |
5454 v8::Debug::DebugBreak(isolate_); | |
5455 threaded_debugging_barriers.barrier_2.Wait(); | |
5456 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_1, buffer)); | |
5457 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_2, buffer)); | |
5458 threaded_debugging_barriers.barrier_4.Wait(); | |
5459 } | |
5460 | |
5461 | |
5462 TEST(ThreadedDebugging) { | |
5463 V8Thread v8_thread; | |
5464 | |
5465 // Create a V8 environment | |
5466 v8_thread.Start(); | |
5467 threaded_debugging_barriers.barrier_3.Wait(); | |
5468 DebuggerThread debugger_thread(v8_thread.isolate()); | |
5469 debugger_thread.Start(); | |
5470 | |
5471 v8_thread.Join(); | |
5472 debugger_thread.Join(); | |
5473 } | |
5474 | |
5475 | |
5476 /* Test RecursiveBreakpoints */ | |
5477 /* In this test, the debugger evaluates a function with a breakpoint, after | |
5478 * hitting a breakpoint in another function. We do this with both values | |
5479 * of the flag enabling recursive breakpoints, and verify that the second | |
5480 * breakpoint is hit when enabled, and missed when disabled. | |
5481 */ | |
5482 | |
5483 class BreakpointsV8Thread : public v8::base::Thread { | |
5484 public: | |
5485 BreakpointsV8Thread() : Thread(Options("BreakpointsV8Thread")) {} | |
5486 void Run(); | |
5487 | |
5488 v8::Isolate* isolate() { return isolate_; } | |
5489 | |
5490 private: | |
5491 v8::Isolate* isolate_; | |
5492 }; | |
5493 | |
5494 class BreakpointsDebuggerThread : public v8::base::Thread { | |
5495 public: | |
5496 BreakpointsDebuggerThread(bool global_evaluate, v8::Isolate* isolate) | |
5497 : Thread(Options("BreakpointsDebuggerThread")), | |
5498 global_evaluate_(global_evaluate), | |
5499 isolate_(isolate) {} | |
5500 void Run(); | |
5501 | |
5502 private: | |
5503 bool global_evaluate_; | |
5504 v8::Isolate* isolate_; | |
5505 }; | |
5506 | |
5507 | |
5508 Barriers* breakpoints_barriers; | |
5509 int break_event_breakpoint_id; | |
5510 int evaluate_int_result; | |
5511 | |
5512 static void BreakpointsMessageHandler(const v8::Debug::Message& message) { | |
5513 static char print_buffer[1000]; | |
5514 v8::String::Value json(message.GetJSON()); | |
5515 Utf16ToAscii(*json, json.length(), print_buffer); | |
5516 | |
5517 if (IsBreakEventMessage(print_buffer)) { | |
5518 break_event_breakpoint_id = | |
5519 GetBreakpointIdFromBreakEventMessage(print_buffer); | |
5520 breakpoints_barriers->semaphore_1.Signal(); | |
5521 } else if (IsEvaluateResponseMessage(print_buffer)) { | |
5522 evaluate_int_result = GetEvaluateIntResult(print_buffer); | |
5523 breakpoints_barriers->semaphore_1.Signal(); | |
5524 } | |
5525 } | |
5526 | |
5527 | |
5528 void BreakpointsV8Thread::Run() { | |
5529 const char* source_1 = "var y_global = 3;\n" | |
5530 "function cat( new_value ) {\n" | |
5531 " var x = new_value;\n" | |
5532 " y_global = y_global + 4;\n" | |
5533 " x = 3 * x + 1;\n" | |
5534 " y_global = y_global + 5;\n" | |
5535 " return x;\n" | |
5536 "}\n" | |
5537 "\n" | |
5538 "function dog() {\n" | |
5539 " var x = 1;\n" | |
5540 " x = y_global;" | |
5541 " var z = 3;" | |
5542 " x += 100;\n" | |
5543 " return x;\n" | |
5544 "}\n" | |
5545 "\n"; | |
5546 const char* source_2 = "cat(17);\n" | |
5547 "cat(19);\n"; | |
5548 | |
5549 v8::Isolate::CreateParams create_params; | |
5550 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); | |
5551 isolate_ = v8::Isolate::New(create_params); | |
5552 breakpoints_barriers->barrier_3.Wait(); | |
5553 { | |
5554 v8::Isolate::Scope isolate_scope(isolate_); | |
5555 DebugLocalContext env(isolate_); | |
5556 v8::HandleScope scope(isolate_); | |
5557 v8::Debug::SetMessageHandler(isolate_, &BreakpointsMessageHandler); | |
5558 | |
5559 CompileRun(source_1); | |
5560 breakpoints_barriers->barrier_1.Wait(); | |
5561 breakpoints_barriers->barrier_2.Wait(); | |
5562 CompileRun(source_2); | |
5563 } | |
5564 breakpoints_barriers->barrier_4.Wait(); | |
5565 isolate_->Dispose(); | |
5566 } | |
5567 | |
5568 | |
5569 void BreakpointsDebuggerThread::Run() { | |
5570 const int kBufSize = 1000; | |
5571 uint16_t buffer[kBufSize]; | |
5572 | |
5573 const char* command_1 = "{\"seq\":101," | |
5574 "\"type\":\"request\"," | |
5575 "\"command\":\"setbreakpoint\"," | |
5576 "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}"; | |
5577 const char* command_2 = "{\"seq\":102," | |
5578 "\"type\":\"request\"," | |
5579 "\"command\":\"setbreakpoint\"," | |
5580 "\"arguments\":{\"type\":\"function\",\"target\":\"dog\",\"line\":3}}"; | |
5581 const char* command_3; | |
5582 if (this->global_evaluate_) { | |
5583 command_3 = "{\"seq\":103," | |
5584 "\"type\":\"request\"," | |
5585 "\"command\":\"evaluate\"," | |
5586 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false," | |
5587 "\"global\":true}}"; | |
5588 } else { | |
5589 command_3 = "{\"seq\":103," | |
5590 "\"type\":\"request\"," | |
5591 "\"command\":\"evaluate\"," | |
5592 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false}}"; | |
5593 } | |
5594 const char* command_4; | |
5595 if (this->global_evaluate_) { | |
5596 command_4 = "{\"seq\":104," | |
5597 "\"type\":\"request\"," | |
5598 "\"command\":\"evaluate\"," | |
5599 "\"arguments\":{\"expression\":\"100 + 8\",\"disable_break\":true," | |
5600 "\"global\":true}}"; | |
5601 } else { | |
5602 command_4 = "{\"seq\":104," | |
5603 "\"type\":\"request\"," | |
5604 "\"command\":\"evaluate\"," | |
5605 "\"arguments\":{\"expression\":\"x + 1\",\"disable_break\":true}}"; | |
5606 } | |
5607 const char* command_5 = "{\"seq\":105," | |
5608 "\"type\":\"request\"," | |
5609 "\"command\":\"continue\"}"; | |
5610 const char* command_6 = "{\"seq\":106," | |
5611 "\"type\":\"request\"," | |
5612 "\"command\":\"continue\"}"; | |
5613 const char* command_7; | |
5614 if (this->global_evaluate_) { | |
5615 command_7 = "{\"seq\":107," | |
5616 "\"type\":\"request\"," | |
5617 "\"command\":\"evaluate\"," | |
5618 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true," | |
5619 "\"global\":true}}"; | |
5620 } else { | |
5621 command_7 = "{\"seq\":107," | |
5622 "\"type\":\"request\"," | |
5623 "\"command\":\"evaluate\"," | |
5624 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true}}"; | |
5625 } | |
5626 const char* command_8 = "{\"seq\":108," | |
5627 "\"type\":\"request\"," | |
5628 "\"command\":\"continue\"}"; | |
5629 | |
5630 | |
5631 // v8 thread initializes, runs source_1 | |
5632 breakpoints_barriers->barrier_1.Wait(); | |
5633 // 1:Set breakpoint in cat() (will get id 1). | |
5634 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_1, buffer)); | |
5635 // 2:Set breakpoint in dog() (will get id 2). | |
5636 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_2, buffer)); | |
5637 breakpoints_barriers->barrier_2.Wait(); | |
5638 // V8 thread starts compiling source_2. | |
5639 // Automatic break happens, to run queued commands | |
5640 // breakpoints_barriers->semaphore_1.Wait(); | |
5641 // Commands 1 through 3 run, thread continues. | |
5642 // v8 thread runs source_2 to breakpoint in cat(). | |
5643 // message callback receives break event. | |
5644 breakpoints_barriers->semaphore_1.Wait(); | |
5645 // Must have hit breakpoint #1. | |
5646 CHECK_EQ(1, break_event_breakpoint_id); | |
5647 // 4:Evaluate dog() (which has a breakpoint). | |
5648 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_3, buffer)); | |
5649 // V8 thread hits breakpoint in dog(). | |
5650 breakpoints_barriers->semaphore_1.Wait(); // wait for break event | |
5651 // Must have hit breakpoint #2. | |
5652 CHECK_EQ(2, break_event_breakpoint_id); | |
5653 // 5:Evaluate (x + 1). | |
5654 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_4, buffer)); | |
5655 // Evaluate (x + 1) finishes. | |
5656 breakpoints_barriers->semaphore_1.Wait(); | |
5657 // Must have result 108. | |
5658 CHECK_EQ(108, evaluate_int_result); | |
5659 // 6:Continue evaluation of dog(). | |
5660 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_5, buffer)); | |
5661 // Evaluate dog() finishes. | |
5662 breakpoints_barriers->semaphore_1.Wait(); | |
5663 // Must have result 107. | |
5664 CHECK_EQ(107, evaluate_int_result); | |
5665 // 7:Continue evaluation of source_2, finish cat(17), hit breakpoint | |
5666 // in cat(19). | |
5667 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_6, buffer)); | |
5668 // Message callback gets break event. | |
5669 breakpoints_barriers->semaphore_1.Wait(); // wait for break event | |
5670 // Must have hit breakpoint #1. | |
5671 CHECK_EQ(1, break_event_breakpoint_id); | |
5672 // 8: Evaluate dog() with breaks disabled. | |
5673 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_7, buffer)); | |
5674 // Evaluate dog() finishes. | |
5675 breakpoints_barriers->semaphore_1.Wait(); | |
5676 // Must have result 116. | |
5677 CHECK_EQ(116, evaluate_int_result); | |
5678 // 9: Continue evaluation of source2, reach end. | |
5679 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_8, buffer)); | |
5680 breakpoints_barriers->barrier_4.Wait(); | |
5681 } | |
5682 | |
5683 | |
5684 void TestRecursiveBreakpointsGeneric(bool global_evaluate) { | |
5685 BreakpointsV8Thread breakpoints_v8_thread; | |
5686 | |
5687 // Create a V8 environment | |
5688 Barriers stack_allocated_breakpoints_barriers; | |
5689 breakpoints_barriers = &stack_allocated_breakpoints_barriers; | |
5690 | |
5691 breakpoints_v8_thread.Start(); | |
5692 breakpoints_barriers->barrier_3.Wait(); | |
5693 BreakpointsDebuggerThread breakpoints_debugger_thread( | |
5694 global_evaluate, breakpoints_v8_thread.isolate()); | |
5695 breakpoints_debugger_thread.Start(); | |
5696 | |
5697 breakpoints_v8_thread.Join(); | |
5698 breakpoints_debugger_thread.Join(); | |
5699 } | |
5700 | |
5701 | |
5702 TEST(RecursiveBreakpoints) { | |
5703 TestRecursiveBreakpointsGeneric(false); | |
5704 } | |
5705 | |
5706 | |
5707 TEST(RecursiveBreakpointsGlobal) { | |
5708 TestRecursiveBreakpointsGeneric(true); | |
5709 } | |
5710 | |
5711 | |
5712 TEST(SetDebugEventListenerOnUninitializedVM) { | 4768 TEST(SetDebugEventListenerOnUninitializedVM) { |
5713 v8::Debug::SetDebugEventListener(CcTest::isolate(), DummyDebugEventListener); | 4769 v8::Debug::SetDebugEventListener(CcTest::isolate(), DummyDebugEventListener); |
5714 } | 4770 } |
5715 | 4771 |
5716 | |
5717 static void DummyMessageHandler(const v8::Debug::Message& message) { | |
5718 } | |
5719 | |
5720 | |
5721 TEST(SetMessageHandlerOnUninitializedVM) { | |
5722 v8::Debug::SetMessageHandler(CcTest::isolate(), DummyMessageHandler); | |
5723 } | |
5724 | |
5725 | |
5726 // Source for a JavaScript function which returns the data parameter of a | 4772 // Source for a JavaScript function which returns the data parameter of a |
5727 // function called in the context of the debugger. If no data parameter is | 4773 // function called in the context of the debugger. If no data parameter is |
5728 // passed it throws an exception. | 4774 // passed it throws an exception. |
5729 static const char* debugger_call_with_data_source = | 4775 static const char* debugger_call_with_data_source = |
5730 "function debugger_call_with_data(exec_state, data) {" | 4776 "function debugger_call_with_data(exec_state, data) {" |
5731 " if (data) return data;" | 4777 " if (data) return data;" |
5732 " throw 'No data!'" | 4778 " throw 'No data!'" |
5733 "}"; | 4779 "}"; |
5734 v8::Local<v8::Function> debugger_call_with_data; | 4780 v8::Local<v8::Function> debugger_call_with_data; |
5735 | 4781 |
(...skipping 188 matching lines...) Loading... |
5924 " CheckSourceLine(9)\n" | 4970 " CheckSourceLine(9)\n" |
5925 " CheckSourceLine(10)\n" | 4971 " CheckSourceLine(10)\n" |
5926 "}; f()"), | 4972 "}; f()"), |
5927 &origin) | 4973 &origin) |
5928 .ToLocalChecked() | 4974 .ToLocalChecked() |
5929 ->Run(context) | 4975 ->Run(context) |
5930 .ToLocalChecked(); | 4976 .ToLocalChecked(); |
5931 } | 4977 } |
5932 | 4978 |
5933 | 4979 |
5934 // Debugger message handler which counts the number of breaks. | |
5935 static void SendContinueCommand(); | |
5936 static void MessageHandlerBreakPointHitCount( | |
5937 const v8::Debug::Message& message) { | |
5938 if (message.IsEvent() && message.GetEvent() == v8::Break) { | |
5939 // Count the number of breaks. | |
5940 break_point_hit_count++; | |
5941 | |
5942 SendContinueCommand(); | |
5943 } | |
5944 } | |
5945 | |
5946 | |
5947 // Test that clearing the debug event listener actually clears all break points | 4980 // Test that clearing the debug event listener actually clears all break points |
5948 // and related information. | 4981 // and related information. |
5949 TEST(DebuggerUnload) { | 4982 TEST(DebuggerUnload) { |
5950 DebugLocalContext env; | 4983 DebugLocalContext env; |
5951 | 4984 |
5952 // Check debugger is unloaded before it is used. | 4985 // Check debugger is unloaded before it is used. |
5953 CheckDebuggerUnloaded(env->GetIsolate()); | 4986 CheckDebuggerUnloaded(env->GetIsolate()); |
5954 | 4987 |
5955 // Set a debug event listener. | 4988 // Set a debug event listener. |
5956 break_point_hit_count = 0; | 4989 break_point_hit_count = 0; |
(...skipping 19 matching lines...) Loading... |
5976 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked(); | 5009 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked(); |
5977 CHECK_EQ(2, break_point_hit_count); | 5010 CHECK_EQ(2, break_point_hit_count); |
5978 bar->Call(context, env->Global(), 0, NULL).ToLocalChecked(); | 5011 bar->Call(context, env->Global(), 0, NULL).ToLocalChecked(); |
5979 CHECK_EQ(4, break_point_hit_count); | 5012 CHECK_EQ(4, break_point_hit_count); |
5980 } | 5013 } |
5981 | 5014 |
5982 // Remove the debug event listener without clearing breakpoints. Do this | 5015 // Remove the debug event listener without clearing breakpoints. Do this |
5983 // outside a handle scope. | 5016 // outside a handle scope. |
5984 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); | 5017 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); |
5985 CheckDebuggerUnloaded(env->GetIsolate(), true); | 5018 CheckDebuggerUnloaded(env->GetIsolate(), true); |
| 5019 } |
5986 | 5020 |
5987 // Now set a debug message handler. | 5021 int event_listener_hit_count = 0; |
5988 break_point_hit_count = 0; | |
5989 v8::Debug::SetMessageHandler(env->GetIsolate(), | |
5990 MessageHandlerBreakPointHitCount); | |
5991 { | |
5992 v8::HandleScope scope(env->GetIsolate()); | |
5993 | 5022 |
5994 // Get the test functions again. | 5023 // Debugger event listener which clears itself while active. |
5995 v8::Local<v8::Function> foo(v8::Local<v8::Function>::Cast( | 5024 static void EventListenerClearingItself( |
5996 env->Global() | 5025 const v8::Debug::EventDetails& details) { |
5997 ->Get(context, v8_str(env->GetIsolate(), "foo")) | 5026 event_listener_hit_count++; |
5998 .ToLocalChecked())); | |
5999 | 5027 |
6000 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked(); | 5028 // Clear debug event listener. |
6001 CHECK_EQ(0, break_point_hit_count); | 5029 v8::Debug::SetDebugEventListener(details.GetIsolate(), nullptr); |
6002 | |
6003 // Set break points and run again. | |
6004 SetBreakPoint(foo, 0); | |
6005 SetBreakPoint(foo, 4); | |
6006 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked(); | |
6007 CHECK_EQ(2, break_point_hit_count); | |
6008 } | |
6009 | |
6010 // Remove the debug message handler without clearing breakpoints. Do this | |
6011 // outside a handle scope. | |
6012 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); | |
6013 CheckDebuggerUnloaded(env->GetIsolate(), true); | |
6014 } | 5030 } |
6015 | 5031 |
6016 | 5032 |
6017 // Sends continue command to the debugger. | 5033 // Test clearing the debug message handler while processing a debug event. |
6018 static void SendContinueCommand() { | 5034 TEST(DebuggerClearEventListenerWhileActive) { |
6019 const int kBufferSize = 1000; | |
6020 uint16_t buffer[kBufferSize]; | |
6021 const char* command_continue = | |
6022 "{\"seq\":0," | |
6023 "\"type\":\"request\"," | |
6024 "\"command\":\"continue\"}"; | |
6025 | |
6026 v8::Debug::SendCommand( | |
6027 CcTest::isolate(), buffer, AsciiToUtf16(command_continue, buffer)); | |
6028 } | |
6029 | |
6030 | |
6031 // Debugger message handler which counts the number of times it is called. | |
6032 static int message_handler_hit_count = 0; | |
6033 static void MessageHandlerHitCount(const v8::Debug::Message& message) { | |
6034 message_handler_hit_count++; | |
6035 | |
6036 static char print_buffer[1000]; | |
6037 v8::String::Value json(message.GetJSON()); | |
6038 Utf16ToAscii(*json, json.length(), print_buffer); | |
6039 if (IsExceptionEventMessage(print_buffer)) { | |
6040 // Send a continue command for exception events. | |
6041 SendContinueCommand(); | |
6042 } | |
6043 } | |
6044 | |
6045 | |
6046 // Test clearing the debug message handler. | |
6047 TEST(DebuggerClearMessageHandler) { | |
6048 DebugLocalContext env; | 5035 DebugLocalContext env; |
6049 v8::HandleScope scope(env->GetIsolate()); | 5036 v8::HandleScope scope(env->GetIsolate()); |
6050 | 5037 |
6051 // Check debugger is unloaded before it is used. | 5038 // Check debugger is unloaded before it is used. |
6052 CheckDebuggerUnloaded(env->GetIsolate()); | 5039 CheckDebuggerUnloaded(env->GetIsolate()); |
6053 | 5040 |
6054 // Set a debug message handler. | 5041 // Set a debug event listener. |
6055 v8::Debug::SetMessageHandler(env->GetIsolate(), MessageHandlerHitCount); | 5042 v8::Debug::SetDebugEventListener(env->GetIsolate(), |
| 5043 EventListenerClearingItself); |
6056 | 5044 |
6057 // Run code to throw a unhandled exception. This should end up in the message | 5045 // Run code to throw an uncaught exception. This should trigger the listener. |
6058 // handler. | |
6059 CompileRun("throw 1"); | 5046 CompileRun("throw 1"); |
6060 | 5047 |
6061 // The message handler should be called. | 5048 // The event listener should have been called. |
6062 CHECK_GT(message_handler_hit_count, 0); | 5049 CHECK_EQ(1, event_listener_hit_count); |
6063 | |
6064 // Clear debug message handler. | |
6065 message_handler_hit_count = 0; | |
6066 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); | |
6067 | |
6068 // Run code to throw a unhandled exception. This should end up in the message | |
6069 // handler. | |
6070 CompileRun("throw 1"); | |
6071 | |
6072 // The message handler should not be called more. | |
6073 CHECK_EQ(0, message_handler_hit_count); | |
6074 | 5050 |
6075 CheckDebuggerUnloaded(env->GetIsolate(), true); | 5051 CheckDebuggerUnloaded(env->GetIsolate(), true); |
6076 } | 5052 } |
6077 | 5053 |
6078 | |
6079 // Debugger message handler which clears the message handler while active. | |
6080 static void MessageHandlerClearingMessageHandler( | |
6081 const v8::Debug::Message& message) { | |
6082 message_handler_hit_count++; | |
6083 | |
6084 // Clear debug message handler. | |
6085 v8::Debug::SetMessageHandler(message.GetIsolate(), nullptr); | |
6086 } | |
6087 | |
6088 | |
6089 // Test clearing the debug message handler while processing a debug event. | |
6090 TEST(DebuggerClearMessageHandlerWhileActive) { | |
6091 DebugLocalContext env; | |
6092 v8::HandleScope scope(env->GetIsolate()); | |
6093 | |
6094 // Check debugger is unloaded before it is used. | |
6095 CheckDebuggerUnloaded(env->GetIsolate()); | |
6096 | |
6097 // Set a debug message handler. | |
6098 v8::Debug::SetMessageHandler(env->GetIsolate(), | |
6099 MessageHandlerClearingMessageHandler); | |
6100 | |
6101 // Run code to throw a unhandled exception. This should end up in the message | |
6102 // handler. | |
6103 CompileRun("throw 1"); | |
6104 | |
6105 // The message handler should be called. | |
6106 CHECK_EQ(1, message_handler_hit_count); | |
6107 | |
6108 CheckDebuggerUnloaded(env->GetIsolate(), true); | |
6109 } | |
6110 | |
6111 | |
6112 // Test for issue http://code.google.com/p/v8/issues/detail?id=289. | 5054 // Test for issue http://code.google.com/p/v8/issues/detail?id=289. |
6113 // Make sure that DebugGetLoadedScripts doesn't return scripts | 5055 // Make sure that DebugGetLoadedScripts doesn't return scripts |
6114 // with disposed external source. | 5056 // with disposed external source. |
6115 class EmptyExternalStringResource : public v8::String::ExternalStringResource { | 5057 class EmptyExternalStringResource : public v8::String::ExternalStringResource { |
6116 public: | 5058 public: |
6117 EmptyExternalStringResource() { empty_[0] = 0; } | 5059 EmptyExternalStringResource() { empty_[0] = 0; } |
6118 virtual ~EmptyExternalStringResource() {} | 5060 virtual ~EmptyExternalStringResource() {} |
6119 virtual size_t length() const { return empty_.length(); } | 5061 virtual size_t length() const { return empty_.length(); } |
6120 virtual const uint16_t* data() const { return empty_.start(); } | 5062 virtual const uint16_t* data() const { return empty_.start(); } |
6121 private: | 5063 private: |
(...skipping 129 matching lines...) Loading... |
6251 f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); | 5193 f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); |
6252 CHECK_EQ(4, break_point_hit_count); | 5194 CHECK_EQ(4, break_point_hit_count); |
6253 } | 5195 } |
6254 | 5196 |
6255 | 5197 |
6256 static v8::Local<v8::Context> expected_context; | 5198 static v8::Local<v8::Context> expected_context; |
6257 static v8::Local<v8::Value> expected_context_data; | 5199 static v8::Local<v8::Value> expected_context_data; |
6258 | 5200 |
6259 | 5201 |
6260 // Check that the expected context is the one generating the debug event. | 5202 // Check that the expected context is the one generating the debug event. |
6261 static void ContextCheckMessageHandler(const v8::Debug::Message& message) { | 5203 static void ContextCheckEventListener( |
6262 CHECK(message.GetEventContext() == expected_context); | 5204 const v8::Debug::EventDetails& event_details) { |
6263 CHECK(message.GetEventContext()->GetEmbedderData(0)->StrictEquals( | 5205 CHECK(event_details.GetEventContext() == expected_context); |
| 5206 CHECK(event_details.GetEventContext()->GetEmbedderData(0)->StrictEquals( |
6264 expected_context_data)); | 5207 expected_context_data)); |
6265 message_handler_hit_count++; | 5208 event_listener_hit_count++; |
6266 | |
6267 static char print_buffer[1000]; | |
6268 v8::String::Value json(message.GetJSON()); | |
6269 Utf16ToAscii(*json, json.length(), print_buffer); | |
6270 | |
6271 // Send a continue command for break events. | |
6272 if (IsBreakEventMessage(print_buffer)) { | |
6273 SendContinueCommand(); | |
6274 } | |
6275 } | 5209 } |
6276 | 5210 |
6277 | 5211 |
6278 // Test which creates two contexts and sets different embedder data on each. | 5212 // Test which creates two contexts and sets different embedder data on each. |
6279 // Checks that this data is set correctly and that when the debug message | 5213 // Checks that this data is set correctly and that when the debug event |
6280 // handler is called the expected context is the one active. | 5214 // listener is called the expected context is the one active. |
6281 TEST(ContextData) { | 5215 TEST(ContextData) { |
6282 v8::Isolate* isolate = CcTest::isolate(); | 5216 v8::Isolate* isolate = CcTest::isolate(); |
6283 v8::HandleScope scope(isolate); | 5217 v8::HandleScope scope(isolate); |
6284 | 5218 |
6285 // Create two contexts. | 5219 // Create two contexts. |
6286 v8::Local<v8::Context> context_1; | 5220 v8::Local<v8::Context> context_1; |
6287 v8::Local<v8::Context> context_2; | 5221 v8::Local<v8::Context> context_2; |
6288 v8::Local<v8::ObjectTemplate> global_template = | 5222 v8::Local<v8::ObjectTemplate> global_template = |
6289 v8::Local<v8::ObjectTemplate>(); | 5223 v8::Local<v8::ObjectTemplate>(); |
6290 v8::Local<v8::Value> global_object = v8::Local<v8::Value>(); | 5224 v8::Local<v8::Value> global_object = v8::Local<v8::Value>(); |
6291 context_1 = v8::Context::New(isolate, NULL, global_template, global_object); | 5225 context_1 = v8::Context::New(isolate, NULL, global_template, global_object); |
6292 context_2 = v8::Context::New(isolate, NULL, global_template, global_object); | 5226 context_2 = v8::Context::New(isolate, NULL, global_template, global_object); |
6293 | 5227 |
6294 v8::Debug::SetMessageHandler(isolate, ContextCheckMessageHandler); | 5228 v8::Debug::SetDebugEventListener(isolate, ContextCheckEventListener); |
6295 | 5229 |
6296 // Default data value is undefined. | 5230 // Default data value is undefined. |
6297 CHECK(context_1->GetEmbedderData(0)->IsUndefined()); | 5231 CHECK(context_1->GetEmbedderData(0)->IsUndefined()); |
6298 CHECK(context_2->GetEmbedderData(0)->IsUndefined()); | 5232 CHECK(context_2->GetEmbedderData(0)->IsUndefined()); |
6299 | 5233 |
6300 // Set and check different data values. | 5234 // Set and check different data values. |
6301 v8::Local<v8::String> data_1 = v8_str(isolate, "1"); | 5235 v8::Local<v8::String> data_1 = v8_str(isolate, "1"); |
6302 v8::Local<v8::String> data_2 = v8_str(isolate, "2"); | 5236 v8::Local<v8::String> data_2 = v8_str(isolate, "2"); |
6303 context_1->SetEmbedderData(0, data_1); | 5237 context_1->SetEmbedderData(0, data_1); |
6304 context_2->SetEmbedderData(0, data_2); | 5238 context_2->SetEmbedderData(0, data_2); |
(...skipping 16 matching lines...) Loading... |
6321 // Enter and run function in the second context. | 5255 // Enter and run function in the second context. |
6322 { | 5256 { |
6323 v8::Context::Scope context_scope(context_2); | 5257 v8::Context::Scope context_scope(context_2); |
6324 expected_context = context_2; | 5258 expected_context = context_2; |
6325 expected_context_data = data_2; | 5259 expected_context_data = data_2; |
6326 v8::Local<v8::Function> f = CompileFunction(isolate, source, "f"); | 5260 v8::Local<v8::Function> f = CompileFunction(isolate, source, "f"); |
6327 f->Call(context_2, context_2->Global(), 0, NULL).ToLocalChecked(); | 5261 f->Call(context_2, context_2->Global(), 0, NULL).ToLocalChecked(); |
6328 } | 5262 } |
6329 | 5263 |
6330 // Two times compile event and two times break event. | 5264 // Two times compile event and two times break event. |
6331 CHECK_GT(message_handler_hit_count, 4); | 5265 CHECK_GT(event_listener_hit_count, 4); |
6332 | 5266 |
6333 v8::Debug::SetMessageHandler(isolate, nullptr); | 5267 v8::Debug::SetDebugEventListener(isolate, nullptr); |
6334 CheckDebuggerUnloaded(isolate); | 5268 CheckDebuggerUnloaded(isolate); |
6335 } | 5269 } |
6336 | 5270 |
6337 | 5271 // Debug event listener which issues a debug break when it hits a break event. |
6338 // Debug message handler which issues a debug break when it hits a break event. | 5272 static int event_listener_break_hit_count = 0; |
6339 static int message_handler_break_hit_count = 0; | 5273 static void DebugBreakEventListener(const v8::Debug::EventDetails& details) { |
6340 static void DebugBreakMessageHandler(const v8::Debug::Message& message) { | |
6341 // Schedule a debug break for break events. | 5274 // Schedule a debug break for break events. |
6342 if (message.IsEvent() && message.GetEvent() == v8::Break) { | 5275 if (details.GetEvent() == v8::Break) { |
6343 message_handler_break_hit_count++; | 5276 event_listener_break_hit_count++; |
6344 if (message_handler_break_hit_count == 1) { | 5277 if (event_listener_break_hit_count == 1) { |
6345 v8::Debug::DebugBreak(message.GetIsolate()); | 5278 v8::Debug::DebugBreak(details.GetIsolate()); |
6346 } | 5279 } |
6347 } | 5280 } |
6348 | |
6349 // Issue a continue command if this event will not cause the VM to start | |
6350 // running. | |
6351 if (!message.WillStartRunning()) { | |
6352 SendContinueCommand(); | |
6353 } | |
6354 } | 5281 } |
6355 | 5282 |
6356 | 5283 // Test that a debug break can be scheduled while in a event listener. |
6357 // Test that a debug break can be scheduled while in a message handler. | 5284 TEST(DebugBreakInEventListener) { |
6358 TEST(DebugBreakInMessageHandler) { | |
6359 i::FLAG_turbo_inlining = false; // Make sure g is not inlined into f. | 5285 i::FLAG_turbo_inlining = false; // Make sure g is not inlined into f. |
6360 DebugLocalContext env; | 5286 DebugLocalContext env; |
6361 v8::HandleScope scope(env->GetIsolate()); | 5287 v8::HandleScope scope(env->GetIsolate()); |
6362 | 5288 |
6363 v8::Debug::SetMessageHandler(env->GetIsolate(), DebugBreakMessageHandler); | 5289 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugBreakEventListener); |
6364 | 5290 |
6365 v8::Local<v8::Context> context = env.context(); | 5291 v8::Local<v8::Context> context = env.context(); |
6366 // Test functions. | 5292 // Test functions. |
6367 const char* script = "function f() { debugger; g(); } function g() { }"; | 5293 const char* script = "function f() { debugger; g(); } function g() { }"; |
6368 CompileRun(script); | 5294 CompileRun(script); |
6369 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( | 5295 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( |
6370 env->Global() | 5296 env->Global() |
6371 ->Get(context, v8_str(env->GetIsolate(), "f")) | 5297 ->Get(context, v8_str(env->GetIsolate(), "f")) |
6372 .ToLocalChecked()); | 5298 .ToLocalChecked()); |
6373 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( | 5299 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( |
6374 env->Global() | 5300 env->Global() |
6375 ->Get(context, v8_str(env->GetIsolate(), "g")) | 5301 ->Get(context, v8_str(env->GetIsolate(), "g")) |
6376 .ToLocalChecked()); | 5302 .ToLocalChecked()); |
6377 | 5303 |
6378 // Call f then g. The debugger statement in f will cause a break which will | 5304 // Call f then g. The debugger statement in f will cause a break which will |
6379 // cause another break. | 5305 // cause another break. |
6380 f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); | 5306 f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); |
6381 CHECK_EQ(2, message_handler_break_hit_count); | 5307 CHECK_EQ(2, event_listener_break_hit_count); |
6382 // Calling g will not cause any additional breaks. | 5308 // Calling g will not cause any additional breaks. |
6383 g->Call(context, env->Global(), 0, NULL).ToLocalChecked(); | 5309 g->Call(context, env->Global(), 0, NULL).ToLocalChecked(); |
6384 CHECK_EQ(2, message_handler_break_hit_count); | 5310 CHECK_EQ(2, event_listener_break_hit_count); |
6385 } | 5311 } |
6386 | 5312 |
6387 | 5313 |
6388 #ifndef V8_INTERPRETED_REGEXP | 5314 #ifndef V8_INTERPRETED_REGEXP |
6389 // Debug event handler which gets the function on the top frame and schedules a | 5315 // Debug event handler which gets the function on the top frame and schedules a |
6390 // break a number of times. | 5316 // break a number of times. |
6391 static void DebugEventDebugBreak( | 5317 static void DebugEventDebugBreak( |
6392 const v8::Debug::EventDetails& event_details) { | 5318 const v8::Debug::EventDetails& event_details) { |
6393 v8::DebugEvent event = event_details.GetEvent(); | 5319 v8::DebugEvent event = event_details.GetEvent(); |
6394 v8::Local<v8::Object> exec_state = event_details.GetExecutionState(); | 5320 v8::Local<v8::Object> exec_state = event_details.GetExecutionState(); |
(...skipping 56 matching lines...) Loading... |
6451 v8::Debug::DebugBreak(env->GetIsolate()); | 5377 v8::Debug::DebugBreak(env->GetIsolate()); |
6452 result = f->Call(context, env->Global(), argc, argv).ToLocalChecked(); | 5378 result = f->Call(context, env->Global(), argc, argv).ToLocalChecked(); |
6453 | 5379 |
6454 // Check that there was only one break event. Matching RegExp should not | 5380 // Check that there was only one break event. Matching RegExp should not |
6455 // cause Break events. | 5381 // cause Break events. |
6456 CHECK_EQ(1, break_point_hit_count); | 5382 CHECK_EQ(1, break_point_hit_count); |
6457 CHECK_EQ(0, strcmp("f", last_function_hit)); | 5383 CHECK_EQ(0, strcmp("f", last_function_hit)); |
6458 } | 5384 } |
6459 #endif // V8_INTERPRETED_REGEXP | 5385 #endif // V8_INTERPRETED_REGEXP |
6460 | 5386 |
| 5387 // Test which creates a context and sets embedder data on it. Checks that this |
| 5388 // data is set correctly and that when the debug event listener is called for |
| 5389 // break event in an eval statement the expected context is the one returned by |
| 5390 // Message.GetEventContext. |
| 5391 TEST(EvalContextData) { |
| 5392 v8::HandleScope scope(CcTest::isolate()); |
6461 | 5393 |
6462 // Common part of EvalContextData and NestedBreakEventContextData tests. | |
6463 static void ExecuteScriptForContextCheck( | |
6464 v8::Debug::MessageHandler message_handler) { | |
6465 // Create a context. | |
6466 v8::Local<v8::Context> context_1; | 5394 v8::Local<v8::Context> context_1; |
6467 v8::Local<v8::ObjectTemplate> global_template = | 5395 v8::Local<v8::ObjectTemplate> global_template = |
6468 v8::Local<v8::ObjectTemplate>(); | 5396 v8::Local<v8::ObjectTemplate>(); |
6469 context_1 = | 5397 context_1 = |
6470 v8::Context::New(CcTest::isolate(), NULL, global_template); | 5398 v8::Context::New(CcTest::isolate(), NULL, global_template); |
6471 | 5399 |
6472 v8::Debug::SetMessageHandler(CcTest::isolate(), message_handler); | 5400 v8::Debug::SetDebugEventListener(CcTest::isolate(), |
| 5401 ContextCheckEventListener); |
6473 | 5402 |
6474 // Default data value is undefined. | 5403 // Default data value is undefined. |
6475 CHECK(context_1->GetEmbedderData(0)->IsUndefined()); | 5404 CHECK(context_1->GetEmbedderData(0)->IsUndefined()); |
6476 | 5405 |
6477 // Set and check a data value. | 5406 // Set and check a data value. |
6478 v8::Local<v8::String> data_1 = v8_str(CcTest::isolate(), "1"); | 5407 v8::Local<v8::String> data_1 = v8_str(CcTest::isolate(), "1"); |
6479 context_1->SetEmbedderData(0, data_1); | 5408 context_1->SetEmbedderData(0, data_1); |
6480 CHECK(context_1->GetEmbedderData(0)->StrictEquals(data_1)); | 5409 CHECK(context_1->GetEmbedderData(0)->StrictEquals(data_1)); |
6481 | 5410 |
6482 // Simple test function with eval that causes a break. | 5411 // Simple test function with eval that causes a break. |
6483 const char* source = "function f() { eval('debugger;'); }"; | 5412 const char* source = "function f() { eval('debugger;'); }"; |
6484 | 5413 |
6485 // Enter and run function in the context. | 5414 // Enter and run function in the context. |
6486 { | 5415 { |
6487 v8::Context::Scope context_scope(context_1); | 5416 v8::Context::Scope context_scope(context_1); |
6488 expected_context = context_1; | 5417 expected_context = context_1; |
6489 expected_context_data = data_1; | 5418 expected_context_data = data_1; |
6490 v8::Local<v8::Function> f = CompileFunction(CcTest::isolate(), source, "f"); | 5419 v8::Local<v8::Function> f = CompileFunction(CcTest::isolate(), source, "f"); |
6491 f->Call(context_1, context_1->Global(), 0, NULL).ToLocalChecked(); | 5420 f->Call(context_1, context_1->Global(), 0, NULL).ToLocalChecked(); |
6492 } | 5421 } |
6493 | 5422 |
6494 v8::Debug::SetMessageHandler(CcTest::isolate(), nullptr); | 5423 v8::Debug::SetDebugEventListener(CcTest::isolate(), nullptr); |
6495 } | |
6496 | |
6497 | |
6498 // Test which creates a context and sets embedder data on it. Checks that this | |
6499 // data is set correctly and that when the debug message handler is called for | |
6500 // break event in an eval statement the expected context is the one returned by | |
6501 // Message.GetEventContext. | |
6502 TEST(EvalContextData) { | |
6503 v8::HandleScope scope(CcTest::isolate()); | |
6504 | |
6505 ExecuteScriptForContextCheck(ContextCheckMessageHandler); | |
6506 | 5424 |
6507 // One time compile event and one time break event. | 5425 // One time compile event and one time break event. |
6508 CHECK_GT(message_handler_hit_count, 2); | 5426 CHECK_GT(event_listener_hit_count, 2); |
6509 CheckDebuggerUnloaded(CcTest::isolate()); | |
6510 } | |
6511 | |
6512 | |
6513 static bool sent_eval = false; | |
6514 static int break_count = 0; | |
6515 static int continue_command_send_count = 0; | |
6516 // Check that the expected context is the one generating the debug event | |
6517 // including the case of nested break event. | |
6518 static void DebugEvalContextCheckMessageHandler( | |
6519 const v8::Debug::Message& message) { | |
6520 CHECK(message.GetEventContext() == expected_context); | |
6521 CHECK(message.GetEventContext()->GetEmbedderData(0)->StrictEquals( | |
6522 expected_context_data)); | |
6523 message_handler_hit_count++; | |
6524 | |
6525 static char print_buffer[1000]; | |
6526 v8::String::Value json(message.GetJSON()); | |
6527 Utf16ToAscii(*json, json.length(), print_buffer); | |
6528 | |
6529 v8::Isolate* isolate = message.GetIsolate(); | |
6530 if (IsBreakEventMessage(print_buffer)) { | |
6531 break_count++; | |
6532 if (!sent_eval) { | |
6533 sent_eval = true; | |
6534 | |
6535 const int kBufferSize = 1000; | |
6536 uint16_t buffer[kBufferSize]; | |
6537 const char* eval_command = | |
6538 "{\"seq\":0," | |
6539 "\"type\":\"request\"," | |
6540 "\"command\":\"evaluate\"," | |
6541 "\"arguments\":{\"expression\":\"debugger;\"," | |
6542 "\"global\":true,\"disable_break\":false}}"; | |
6543 | |
6544 // Send evaluate command. | |
6545 v8::Debug::SendCommand( | |
6546 isolate, buffer, AsciiToUtf16(eval_command, buffer)); | |
6547 return; | |
6548 } else { | |
6549 // It's a break event caused by the evaluation request above. | |
6550 SendContinueCommand(); | |
6551 continue_command_send_count++; | |
6552 } | |
6553 } else if (IsEvaluateResponseMessage(print_buffer) && | |
6554 continue_command_send_count < 2) { | |
6555 // Response to the evaluation request. We're still on the breakpoint so | |
6556 // send continue. | |
6557 SendContinueCommand(); | |
6558 continue_command_send_count++; | |
6559 } | |
6560 } | |
6561 | |
6562 | |
6563 // Tests that context returned for break event is correct when the event occurs | |
6564 // in 'evaluate' debugger request. | |
6565 TEST(NestedBreakEventContextData) { | |
6566 v8::HandleScope scope(CcTest::isolate()); | |
6567 break_count = 0; | |
6568 message_handler_hit_count = 0; | |
6569 | |
6570 ExecuteScriptForContextCheck(DebugEvalContextCheckMessageHandler); | |
6571 | |
6572 // One time compile event and two times break event. | |
6573 CHECK_GT(message_handler_hit_count, 3); | |
6574 | |
6575 // One break from the source and another from the evaluate request. | |
6576 CHECK_EQ(break_count, 2); | |
6577 CheckDebuggerUnloaded(CcTest::isolate()); | 5427 CheckDebuggerUnloaded(CcTest::isolate()); |
6578 } | 5428 } |
6579 | 5429 |
6580 | 5430 |
6581 // Debug event listener which counts the after compile events. | 5431 // Debug event listener which counts the after compile events. |
6582 int after_compile_message_count = 0; | 5432 int after_compile_event_count = 0; |
6583 static void AfterCompileMessageHandler(const v8::Debug::Message& message) { | 5433 static void AfterCompileEventListener(const v8::Debug::EventDetails& details) { |
6584 // Count the number of scripts collected. | 5434 // Count the number of scripts collected. |
6585 if (message.IsEvent()) { | 5435 if (details.GetEvent() == v8::AfterCompile) { |
6586 if (message.GetEvent() == v8::AfterCompile) { | 5436 after_compile_event_count++; |
6587 after_compile_message_count++; | |
6588 } else if (message.GetEvent() == v8::Break) { | |
6589 SendContinueCommand(); | |
6590 } | |
6591 } | 5437 } |
6592 } | 5438 } |
6593 | 5439 |
6594 | 5440 |
6595 // Tests that after compile event is sent as many times as there are scripts | 5441 // Tests that after compile event is sent as many times as there are scripts |
6596 // compiled. | 5442 // compiled. |
6597 TEST(AfterCompileMessageWhenMessageHandlerIsReset) { | 5443 TEST(AfterCompileEventWhenEventListenerIsReset) { |
6598 DebugLocalContext env; | 5444 DebugLocalContext env; |
6599 v8::HandleScope scope(env->GetIsolate()); | 5445 v8::HandleScope scope(env->GetIsolate()); |
6600 v8::Local<v8::Context> context = env.context(); | 5446 v8::Local<v8::Context> context = env.context(); |
6601 after_compile_message_count = 0; | |
6602 const char* script = "var a=1"; | 5447 const char* script = "var a=1"; |
6603 | 5448 |
6604 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler); | 5449 v8::Debug::SetDebugEventListener(env->GetIsolate(), |
| 5450 AfterCompileEventListener); |
6605 v8::Script::Compile(context, v8_str(env->GetIsolate(), script)) | 5451 v8::Script::Compile(context, v8_str(env->GetIsolate(), script)) |
6606 .ToLocalChecked() | 5452 .ToLocalChecked() |
6607 ->Run(context) | 5453 ->Run(context) |
6608 .ToLocalChecked(); | 5454 .ToLocalChecked(); |
6609 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); | 5455 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); |
6610 | 5456 |
6611 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler); | 5457 v8::Debug::SetDebugEventListener(env->GetIsolate(), |
| 5458 AfterCompileEventListener); |
6612 v8::Debug::DebugBreak(env->GetIsolate()); | 5459 v8::Debug::DebugBreak(env->GetIsolate()); |
6613 v8::Script::Compile(context, v8_str(env->GetIsolate(), script)) | 5460 v8::Script::Compile(context, v8_str(env->GetIsolate(), script)) |
6614 .ToLocalChecked() | 5461 .ToLocalChecked() |
6615 ->Run(context) | 5462 ->Run(context) |
6616 .ToLocalChecked(); | 5463 .ToLocalChecked(); |
6617 | 5464 |
6618 // Setting listener to NULL should cause debugger unload. | 5465 // Setting listener to NULL should cause debugger unload. |
6619 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); | 5466 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); |
6620 CheckDebuggerUnloaded(env->GetIsolate()); | 5467 CheckDebuggerUnloaded(env->GetIsolate()); |
6621 | 5468 |
6622 // Compilation cache should be disabled when debugger is active. | 5469 // Compilation cache should be disabled when debugger is active. |
6623 CHECK_EQ(2, after_compile_message_count); | 5470 CHECK_EQ(2, after_compile_event_count); |
6624 } | 5471 } |
6625 | 5472 |
6626 | 5473 |
6627 // Syntax error event handler which counts a number of events. | 5474 // Syntax error event handler which counts a number of events. |
6628 int compile_error_event_count = 0; | 5475 int compile_error_event_count = 0; |
6629 | 5476 |
6630 static void CompileErrorEventCounterClear() { | 5477 static void CompileErrorEventCounterClear() { |
6631 compile_error_event_count = 0; | 5478 compile_error_event_count = 0; |
6632 } | 5479 } |
6633 | 5480 |
6634 static void CompileErrorEventCounter( | 5481 static void CompileErrorEventCounter( |
6635 const v8::Debug::EventDetails& event_details) { | 5482 const v8::Debug::EventDetails& event_details) { |
6636 v8::DebugEvent event = event_details.GetEvent(); | 5483 v8::DebugEvent event = event_details.GetEvent(); |
6637 | 5484 |
6638 if (event == v8::CompileError) { | 5485 if (event == v8::CompileError) { |
6639 compile_error_event_count++; | 5486 compile_error_event_count++; |
6640 } | 5487 } |
6641 } | 5488 } |
6642 | 5489 |
6643 | 5490 |
6644 // Tests that syntax error event is sent as many times as there are scripts | 5491 // Tests that syntax error event is sent as many times as there are scripts |
6645 // with syntax error compiled. | 5492 // with syntax error compiled. |
6646 TEST(SyntaxErrorMessageOnSyntaxException) { | 5493 TEST(SyntaxErrorEventOnSyntaxException) { |
6647 DebugLocalContext env; | 5494 DebugLocalContext env; |
6648 v8::HandleScope scope(env->GetIsolate()); | 5495 v8::HandleScope scope(env->GetIsolate()); |
6649 | 5496 |
6650 // For this test, we want to break on uncaught exceptions: | 5497 // For this test, we want to break on uncaught exceptions: |
6651 ChangeBreakOnException(false, true); | 5498 ChangeBreakOnException(false, true); |
6652 | 5499 |
6653 v8::Debug::SetDebugEventListener(env->GetIsolate(), CompileErrorEventCounter); | 5500 v8::Debug::SetDebugEventListener(env->GetIsolate(), CompileErrorEventCounter); |
6654 v8::Local<v8::Context> context = env.context(); | 5501 v8::Local<v8::Context> context = env.context(); |
6655 | 5502 |
6656 CompileErrorEventCounterClear(); | 5503 CompileErrorEventCounterClear(); |
(...skipping 21 matching lines...) Loading... |
6678 v8::Script::Compile(context, | 5525 v8::Script::Compile(context, |
6679 v8_str(env->GetIsolate(), "new RegExp('/\\/\\\\');")) | 5526 v8_str(env->GetIsolate(), "new RegExp('/\\/\\\\');")) |
6680 .ToLocalChecked(); | 5527 .ToLocalChecked(); |
6681 CHECK_EQ(3, compile_error_event_count); | 5528 CHECK_EQ(3, compile_error_event_count); |
6682 | 5529 |
6683 v8::Script::Compile(context, v8_str(env->GetIsolate(), "throw 1;")) | 5530 v8::Script::Compile(context, v8_str(env->GetIsolate(), "throw 1;")) |
6684 .ToLocalChecked(); | 5531 .ToLocalChecked(); |
6685 CHECK_EQ(3, compile_error_event_count); | 5532 CHECK_EQ(3, compile_error_event_count); |
6686 } | 5533 } |
6687 | 5534 |
6688 | 5535 // Tests that break event is sent when event listener is reset. |
6689 // Tests that break event is sent when message handler is reset. | 5536 TEST(BreakEventWhenEventListenerIsReset) { |
6690 TEST(BreakMessageWhenMessageHandlerIsReset) { | |
6691 DebugLocalContext env; | 5537 DebugLocalContext env; |
6692 v8::HandleScope scope(env->GetIsolate()); | 5538 v8::HandleScope scope(env->GetIsolate()); |
6693 v8::Local<v8::Context> context = env.context(); | 5539 v8::Local<v8::Context> context = env.context(); |
6694 after_compile_message_count = 0; | |
6695 const char* script = "function f() {};"; | 5540 const char* script = "function f() {};"; |
6696 | 5541 |
6697 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler); | 5542 v8::Debug::SetDebugEventListener(env->GetIsolate(), |
| 5543 AfterCompileEventListener); |
6698 v8::Script::Compile(context, v8_str(env->GetIsolate(), script)) | 5544 v8::Script::Compile(context, v8_str(env->GetIsolate(), script)) |
6699 .ToLocalChecked() | 5545 .ToLocalChecked() |
6700 ->Run(context) | 5546 ->Run(context) |
6701 .ToLocalChecked(); | 5547 .ToLocalChecked(); |
6702 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); | 5548 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); |
6703 | 5549 |
6704 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler); | 5550 v8::Debug::SetDebugEventListener(env->GetIsolate(), |
| 5551 AfterCompileEventListener); |
6705 v8::Debug::DebugBreak(env->GetIsolate()); | 5552 v8::Debug::DebugBreak(env->GetIsolate()); |
6706 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( | 5553 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( |
6707 env->Global() | 5554 env->Global() |
6708 ->Get(context, v8_str(env->GetIsolate(), "f")) | 5555 ->Get(context, v8_str(env->GetIsolate(), "f")) |
6709 .ToLocalChecked()); | 5556 .ToLocalChecked()); |
6710 f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); | 5557 f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); |
6711 | 5558 |
6712 // Setting message handler to NULL should cause debugger unload. | 5559 // Setting event listener to NULL should cause debugger unload. |
6713 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); | 5560 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); |
6714 CheckDebuggerUnloaded(env->GetIsolate()); | 5561 CheckDebuggerUnloaded(env->GetIsolate()); |
6715 | 5562 |
6716 // Compilation cache should be disabled when debugger is active. | 5563 // Compilation cache should be disabled when debugger is active. |
6717 CHECK_EQ(1, after_compile_message_count); | 5564 CHECK_EQ(1, after_compile_event_count); |
6718 } | 5565 } |
6719 | 5566 |
6720 | 5567 |
6721 static int exception_event_count = 0; | 5568 static int exception_event_count = 0; |
6722 static void ExceptionMessageHandler(const v8::Debug::Message& message) { | 5569 static void ExceptionEventListener(const v8::Debug::EventDetails& details) { |
6723 if (message.IsEvent() && message.GetEvent() == v8::Exception) { | 5570 if (details.GetEvent() == v8::Exception) exception_event_count++; |
6724 exception_event_count++; | |
6725 SendContinueCommand(); | |
6726 } | |
6727 } | 5571 } |
6728 | 5572 |
6729 | 5573 // Tests that exception event is sent when event listener is reset. |
6730 // Tests that exception event is sent when message handler is reset. | 5574 TEST(ExceptionEventWhenEventListenerIsReset) { |
6731 TEST(ExceptionMessageWhenMessageHandlerIsReset) { | |
6732 DebugLocalContext env; | 5575 DebugLocalContext env; |
6733 v8::HandleScope scope(env->GetIsolate()); | 5576 v8::HandleScope scope(env->GetIsolate()); |
6734 | 5577 |
6735 v8::Local<v8::Context> context = env.context(); | 5578 v8::Local<v8::Context> context = env.context(); |
6736 // For this test, we want to break on uncaught exceptions: | 5579 // For this test, we want to break on uncaught exceptions: |
6737 ChangeBreakOnException(false, true); | 5580 ChangeBreakOnException(false, true); |
6738 | 5581 |
6739 exception_event_count = 0; | 5582 exception_event_count = 0; |
6740 const char* script = "function f() {throw new Error()};"; | 5583 const char* script = "function f() {throw new Error()};"; |
6741 | 5584 |
6742 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler); | 5585 v8::Debug::SetDebugEventListener(env->GetIsolate(), |
| 5586 AfterCompileEventListener); |
6743 v8::Script::Compile(context, v8_str(env->GetIsolate(), script)) | 5587 v8::Script::Compile(context, v8_str(env->GetIsolate(), script)) |
6744 .ToLocalChecked() | 5588 .ToLocalChecked() |
6745 ->Run(context) | 5589 ->Run(context) |
6746 .ToLocalChecked(); | 5590 .ToLocalChecked(); |
6747 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); | 5591 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); |
6748 | 5592 |
6749 v8::Debug::SetMessageHandler(env->GetIsolate(), ExceptionMessageHandler); | 5593 v8::Debug::SetDebugEventListener(env->GetIsolate(), ExceptionEventListener); |
6750 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( | 5594 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( |
6751 env->Global() | 5595 env->Global() |
6752 ->Get(context, v8_str(env->GetIsolate(), "f")) | 5596 ->Get(context, v8_str(env->GetIsolate(), "f")) |
6753 .ToLocalChecked()); | 5597 .ToLocalChecked()); |
6754 CHECK(f->Call(context, env->Global(), 0, NULL).IsEmpty()); | 5598 CHECK(f->Call(context, env->Global(), 0, NULL).IsEmpty()); |
6755 | 5599 |
6756 // Setting message handler to NULL should cause debugger unload. | 5600 // Setting event listener to NULL should cause debugger unload. |
6757 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); | 5601 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); |
6758 CheckDebuggerUnloaded(env->GetIsolate()); | 5602 CheckDebuggerUnloaded(env->GetIsolate()); |
6759 | 5603 |
6760 CHECK_EQ(1, exception_event_count); | 5604 CHECK_EQ(1, exception_event_count); |
6761 } | 5605 } |
6762 | 5606 |
6763 | 5607 |
6764 // Tests after compile event is sent when there are some provisional | 5608 // Tests after compile event is sent when there are some provisional |
6765 // breakpoints out of the scripts lines range. | 5609 // breakpoints out of the scripts lines range. |
6766 TEST(ProvisionalBreakpointOnLineOutOfRange) { | 5610 TEST(ProvisionalBreakpointOnLineOutOfRange) { |
6767 DebugLocalContext env; | 5611 DebugLocalContext env; |
6768 v8::HandleScope scope(env->GetIsolate()); | 5612 v8::HandleScope scope(env->GetIsolate()); |
6769 env.ExposeDebug(); | 5613 env.ExposeDebug(); |
6770 const char* script = "function f() {};"; | 5614 const char* script = "function f() {};"; |
6771 const char* resource_name = "test_resource"; | 5615 const char* resource_name = "test_resource"; |
6772 | 5616 |
6773 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler); | 5617 v8::Debug::SetDebugEventListener(env->GetIsolate(), |
| 5618 AfterCompileEventListener); |
6774 v8::Local<v8::Context> context = env.context(); | 5619 v8::Local<v8::Context> context = env.context(); |
6775 | 5620 |
6776 // Set a couple of provisional breakpoint on lines out of the script lines | 5621 // Set a couple of provisional breakpoint on lines out of the script lines |
6777 // range. | 5622 // range. |
6778 int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name, | 5623 int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name, |
6779 3, -1 /* no column */); | 5624 3, -1 /* no column */); |
6780 int sbp2 = | 5625 int sbp2 = |
6781 SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name, 5, 5); | 5626 SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name, 5, 5); |
6782 | 5627 |
6783 after_compile_message_count = 0; | 5628 after_compile_event_count = 0; |
6784 | 5629 |
6785 v8::ScriptOrigin origin(v8_str(env->GetIsolate(), resource_name), | 5630 v8::ScriptOrigin origin(v8_str(env->GetIsolate(), resource_name), |
6786 v8::Integer::New(env->GetIsolate(), 10), | 5631 v8::Integer::New(env->GetIsolate(), 10), |
6787 v8::Integer::New(env->GetIsolate(), 1)); | 5632 v8::Integer::New(env->GetIsolate(), 1)); |
6788 // Compile a script whose first line number is greater than the breakpoints' | 5633 // Compile a script whose first line number is greater than the breakpoints' |
6789 // lines. | 5634 // lines. |
6790 v8::Script::Compile(context, v8_str(env->GetIsolate(), script), &origin) | 5635 v8::Script::Compile(context, v8_str(env->GetIsolate(), script), &origin) |
6791 .ToLocalChecked() | 5636 .ToLocalChecked() |
6792 ->Run(context) | 5637 ->Run(context) |
6793 .ToLocalChecked(); | 5638 .ToLocalChecked(); |
6794 | 5639 |
6795 // If the script is compiled successfully there is exactly one after compile | 5640 // If the script is compiled successfully there is exactly one after compile |
6796 // event. In case of an exception in debugger code after compile event is not | 5641 // event. In case of an exception in debugger code after compile event is not |
6797 // sent. | 5642 // sent. |
6798 CHECK_EQ(1, after_compile_message_count); | 5643 CHECK_EQ(1, after_compile_event_count); |
6799 | 5644 |
6800 ClearBreakPointFromJS(env->GetIsolate(), sbp1); | 5645 ClearBreakPointFromJS(env->GetIsolate(), sbp1); |
6801 ClearBreakPointFromJS(env->GetIsolate(), sbp2); | 5646 ClearBreakPointFromJS(env->GetIsolate(), sbp2); |
6802 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); | 5647 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); |
| 5648 CheckDebuggerUnloaded(env->GetIsolate()); |
6803 } | 5649 } |
6804 | 5650 |
6805 | 5651 static void BreakEventListener(const v8::Debug::EventDetails& details) { |
6806 static void BreakMessageHandler(const v8::Debug::Message& message) { | |
6807 i::Isolate* isolate = CcTest::i_isolate(); | 5652 i::Isolate* isolate = CcTest::i_isolate(); |
6808 if (message.IsEvent() && message.GetEvent() == v8::Break) { | 5653 if (details.GetEvent() == v8::Break) break_point_hit_count++; |
6809 // Count the number of breaks. | |
6810 break_point_hit_count++; | |
6811 | |
6812 i::HandleScope scope(isolate); | |
6813 message.GetJSON(); | |
6814 | |
6815 SendContinueCommand(); | |
6816 } else if (message.IsEvent() && message.GetEvent() == v8::AfterCompile) { | |
6817 i::HandleScope scope(isolate); | |
6818 | |
6819 int current_count = break_point_hit_count; | |
6820 | |
6821 // Force serialization to trigger some internal JS execution. | |
6822 message.GetJSON(); | |
6823 | |
6824 CHECK_EQ(current_count, break_point_hit_count); | |
6825 } | |
6826 } | 5654 } |
6827 | 5655 |
6828 | 5656 |
6829 // Test that if DebugBreak is forced it is ignored when code from | 5657 // Test that if DebugBreak is forced it is ignored when code from |
6830 // debug-delay.js is executed. | 5658 // debug-delay.js is executed. |
6831 TEST(NoDebugBreakInAfterCompileMessageHandler) { | 5659 TEST(NoDebugBreakInAfterCompileEventListener) { |
6832 DebugLocalContext env; | 5660 DebugLocalContext env; |
6833 v8::HandleScope scope(env->GetIsolate()); | 5661 v8::HandleScope scope(env->GetIsolate()); |
6834 v8::Local<v8::Context> context = env.context(); | 5662 v8::Local<v8::Context> context = env.context(); |
6835 | 5663 |
6836 // Register a debug event listener which sets the break flag and counts. | 5664 // Register a debug event listener which sets the break flag and counts. |
6837 v8::Debug::SetMessageHandler(env->GetIsolate(), BreakMessageHandler); | 5665 v8::Debug::SetDebugEventListener(env->GetIsolate(), BreakEventListener); |
6838 | 5666 |
6839 // Set the debug break flag. | 5667 // Set the debug break flag. |
6840 v8::Debug::DebugBreak(env->GetIsolate()); | 5668 v8::Debug::DebugBreak(env->GetIsolate()); |
6841 | 5669 |
6842 // Create a function for testing stepping. | 5670 // Create a function for testing stepping. |
6843 const char* src = "function f() { eval('var x = 10;'); } "; | 5671 const char* src = "function f() { eval('var x = 10;'); } "; |
6844 v8::Local<v8::Function> f = CompileFunction(&env, src, "f"); | 5672 v8::Local<v8::Function> f = CompileFunction(&env, src, "f"); |
6845 | 5673 |
6846 // There should be only one break event. | 5674 // There should be only one break event. |
6847 CHECK_EQ(1, break_point_hit_count); | 5675 CHECK_EQ(1, break_point_hit_count); |
6848 | 5676 |
6849 // Set the debug break flag again. | 5677 // Set the debug break flag again. |
6850 v8::Debug::DebugBreak(env->GetIsolate()); | 5678 v8::Debug::DebugBreak(env->GetIsolate()); |
6851 f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); | 5679 f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); |
6852 // There should be one more break event when the script is evaluated in 'f'. | 5680 // There should be one more break event when the script is evaluated in 'f'. |
6853 CHECK_EQ(2, break_point_hit_count); | 5681 CHECK_EQ(2, break_point_hit_count); |
6854 | 5682 |
6855 // Get rid of the debug message handler. | 5683 // Get rid of the debug event listener. |
6856 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr); | 5684 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); |
6857 CheckDebuggerUnloaded(env->GetIsolate()); | 5685 CheckDebuggerUnloaded(env->GetIsolate()); |
6858 } | 5686 } |
6859 | 5687 |
6860 | 5688 |
6861 static int counting_message_handler_counter; | |
6862 | |
6863 static void CountingMessageHandler(const v8::Debug::Message& message) { | |
6864 if (message.IsResponse()) counting_message_handler_counter++; | |
6865 } | |
6866 | |
6867 | |
6868 // Test that debug messages get processed when ProcessDebugMessages is called. | |
6869 TEST(ProcessDebugMessages) { | |
6870 DebugLocalContext env; | |
6871 v8::Isolate* isolate = env->GetIsolate(); | |
6872 v8::HandleScope scope(isolate); | |
6873 | |
6874 counting_message_handler_counter = 0; | |
6875 | |
6876 v8::Debug::SetMessageHandler(isolate, CountingMessageHandler); | |
6877 | |
6878 const int kBufferSize = 1000; | |
6879 uint16_t buffer[kBufferSize]; | |
6880 const char* scripts_command = | |
6881 "{\"seq\":0," | |
6882 "\"type\":\"request\"," | |
6883 "\"command\":\"scripts\"}"; | |
6884 | |
6885 // Send scripts command. | |
6886 v8::Debug::SendCommand( | |
6887 isolate, buffer, AsciiToUtf16(scripts_command, buffer)); | |
6888 | |
6889 CHECK_EQ(0, counting_message_handler_counter); | |
6890 v8::Debug::ProcessDebugMessages(isolate); | |
6891 // At least one message should come | |
6892 CHECK_GE(counting_message_handler_counter, 1); | |
6893 | |
6894 counting_message_handler_counter = 0; | |
6895 | |
6896 v8::Debug::SendCommand( | |
6897 isolate, buffer, AsciiToUtf16(scripts_command, buffer)); | |
6898 v8::Debug::SendCommand( | |
6899 isolate, buffer, AsciiToUtf16(scripts_command, buffer)); | |
6900 CHECK_EQ(0, counting_message_handler_counter); | |
6901 v8::Debug::ProcessDebugMessages(isolate); | |
6902 // At least two messages should come | |
6903 CHECK_GE(counting_message_handler_counter, 2); | |
6904 | |
6905 // Get rid of the debug message handler. | |
6906 v8::Debug::SetMessageHandler(isolate, nullptr); | |
6907 CheckDebuggerUnloaded(isolate); | |
6908 } | |
6909 | |
6910 | |
6911 class SendCommandThread; | |
6912 static SendCommandThread* send_command_thread_ = NULL; | |
6913 | |
6914 | |
6915 class SendCommandThread : public v8::base::Thread { | |
6916 public: | |
6917 explicit SendCommandThread(v8::Isolate* isolate) | |
6918 : Thread(Options("SendCommandThread")), | |
6919 semaphore_(0), | |
6920 isolate_(isolate) {} | |
6921 | |
6922 static void CountingAndSignallingMessageHandler( | |
6923 const v8::Debug::Message& message) { | |
6924 if (message.IsResponse()) { | |
6925 counting_message_handler_counter++; | |
6926 send_command_thread_->semaphore_.Signal(); | |
6927 } | |
6928 } | |
6929 | |
6930 virtual void Run() { | |
6931 semaphore_.Wait(); | |
6932 const int kBufferSize = 1000; | |
6933 uint16_t buffer[kBufferSize]; | |
6934 const char* scripts_command = | |
6935 "{\"seq\":0," | |
6936 "\"type\":\"request\"," | |
6937 "\"command\":\"scripts\"}"; | |
6938 int length = AsciiToUtf16(scripts_command, buffer); | |
6939 // Send scripts command. | |
6940 | |
6941 for (int i = 0; i < 20; i++) { | |
6942 v8::base::ElapsedTimer timer; | |
6943 timer.Start(); | |
6944 CHECK_EQ(i, counting_message_handler_counter); | |
6945 // Queue debug message. | |
6946 v8::Debug::SendCommand(isolate_, buffer, length); | |
6947 // Wait for the message handler to pick up the response. | |
6948 semaphore_.Wait(); | |
6949 i::PrintF("iteration %d took %f ms\n", i, | |
6950 timer.Elapsed().InMillisecondsF()); | |
6951 } | |
6952 | |
6953 isolate_->TerminateExecution(); | |
6954 } | |
6955 | |
6956 void StartSending() { semaphore_.Signal(); } | |
6957 | |
6958 private: | |
6959 v8::base::Semaphore semaphore_; | |
6960 v8::Isolate* isolate_; | |
6961 }; | |
6962 | |
6963 | |
6964 static void StartSendingCommands( | |
6965 const v8::FunctionCallbackInfo<v8::Value>& info) { | |
6966 send_command_thread_->StartSending(); | |
6967 } | |
6968 | |
6969 | |
6970 TEST(ProcessDebugMessagesThreaded) { | |
6971 DebugLocalContext env; | |
6972 v8::Isolate* isolate = env->GetIsolate(); | |
6973 v8::HandleScope scope(isolate); | |
6974 v8::Local<v8::Context> context = env.context(); | |
6975 | |
6976 counting_message_handler_counter = 0; | |
6977 | |
6978 v8::Debug::SetMessageHandler( | |
6979 isolate, SendCommandThread::CountingAndSignallingMessageHandler); | |
6980 send_command_thread_ = new SendCommandThread(isolate); | |
6981 send_command_thread_->Start(); | |
6982 | |
6983 v8::Local<v8::FunctionTemplate> start = | |
6984 v8::FunctionTemplate::New(isolate, StartSendingCommands); | |
6985 CHECK(env->Global() | |
6986 ->Set(context, v8_str("start"), | |
6987 start->GetFunction(context).ToLocalChecked()) | |
6988 .FromJust()); | |
6989 | |
6990 CompileRun("start(); while (true) { }"); | |
6991 | |
6992 CHECK_EQ(20, counting_message_handler_counter); | |
6993 | |
6994 v8::Debug::SetMessageHandler(isolate, nullptr); | |
6995 CheckDebuggerUnloaded(isolate); | |
6996 } | |
6997 | |
6998 | |
6999 struct BacktraceData { | |
7000 static int frame_counter; | |
7001 static void MessageHandler(const v8::Debug::Message& message) { | |
7002 char print_buffer[1000]; | |
7003 v8::String::Value json(message.GetJSON()); | |
7004 Utf16ToAscii(*json, json.length(), print_buffer, 1000); | |
7005 | |
7006 if (strstr(print_buffer, "backtrace") == NULL) { | |
7007 return; | |
7008 } | |
7009 frame_counter = GetTotalFramesInt(print_buffer); | |
7010 } | |
7011 }; | |
7012 | |
7013 int BacktraceData::frame_counter; | |
7014 | |
7015 | |
7016 // Test that debug messages get processed when ProcessDebugMessages is called. | |
7017 TEST(Backtrace) { | |
7018 DebugLocalContext env; | |
7019 v8::Isolate* isolate = env->GetIsolate(); | |
7020 v8::HandleScope scope(isolate); | |
7021 v8::Local<v8::Context> context = env.context(); | |
7022 | |
7023 v8::Debug::SetMessageHandler(isolate, BacktraceData::MessageHandler); | |
7024 | |
7025 const int kBufferSize = 1000; | |
7026 uint16_t buffer[kBufferSize]; | |
7027 const char* scripts_command = | |
7028 "{\"seq\":0," | |
7029 "\"type\":\"request\"," | |
7030 "\"command\":\"backtrace\"}"; | |
7031 | |
7032 // Check backtrace from ProcessDebugMessages. | |
7033 BacktraceData::frame_counter = -10; | |
7034 v8::Debug::SendCommand( | |
7035 isolate, | |
7036 buffer, | |
7037 AsciiToUtf16(scripts_command, buffer), | |
7038 NULL); | |
7039 v8::Debug::ProcessDebugMessages(isolate); | |
7040 CHECK_EQ(BacktraceData::frame_counter, 0); | |
7041 | |
7042 v8::Local<v8::String> void0 = v8_str(env->GetIsolate(), "void(0)"); | |
7043 v8::Local<v8::Script> script = CompileWithOrigin(void0, void0); | |
7044 | |
7045 // Check backtrace from "void(0)" script. | |
7046 BacktraceData::frame_counter = -10; | |
7047 v8::Debug::SendCommand( | |
7048 isolate, | |
7049 buffer, | |
7050 AsciiToUtf16(scripts_command, buffer), | |
7051 NULL); | |
7052 script->Run(context).ToLocalChecked(); | |
7053 CHECK_EQ(BacktraceData::frame_counter, 1); | |
7054 | |
7055 // Get rid of the debug message handler. | |
7056 v8::Debug::SetMessageHandler(isolate, nullptr); | |
7057 CheckDebuggerUnloaded(isolate); | |
7058 } | |
7059 | |
7060 | |
7061 TEST(GetMirror) { | 5689 TEST(GetMirror) { |
7062 DebugLocalContext env; | 5690 DebugLocalContext env; |
7063 v8::Isolate* isolate = env->GetIsolate(); | 5691 v8::Isolate* isolate = env->GetIsolate(); |
7064 v8::HandleScope scope(isolate); | 5692 v8::HandleScope scope(isolate); |
7065 v8::Local<v8::Context> context = env.context(); | 5693 v8::Local<v8::Context> context = env.context(); |
7066 v8::Local<v8::Value> obj = | 5694 v8::Local<v8::Value> obj = |
7067 v8::Debug::GetMirror(context, v8_str(isolate, "hodja")).ToLocalChecked(); | 5695 v8::Debug::GetMirror(context, v8_str(isolate, "hodja")).ToLocalChecked(); |
7068 v8::ScriptCompiler::Source source(v8_str( | 5696 v8::ScriptCompiler::Source source(v8_str( |
7069 "function runTest(mirror) {" | 5697 "function runTest(mirror) {" |
7070 " return mirror.isString() && (mirror.length() == 5);" | 5698 " return mirror.isString() && (mirror.length() == 5);" |
(...skipping 1159 matching lines...) Loading... |
8230 "function foo() {\n" | 6858 "function foo() {\n" |
8231 " try { throw new Error(); } catch (e) {}\n" | 6859 " try { throw new Error(); } catch (e) {}\n" |
8232 "}\n" | 6860 "}\n" |
8233 "debugger;\n" | 6861 "debugger;\n" |
8234 "foo();\n" | 6862 "foo();\n" |
8235 "foo();\n"); | 6863 "foo();\n"); |
8236 | 6864 |
8237 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); | 6865 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); |
8238 CHECK_EQ(break_point_hit_count, 4); | 6866 CHECK_EQ(break_point_hit_count, 4); |
8239 } | 6867 } |
OLD | NEW |