| 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...) Expand all 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...) Expand 10 before | Expand all | Expand 10 after 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...) Expand 10 before | Expand all | Expand 10 after 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...) Expand 10 before | Expand all | Expand 10 after 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...) Expand 10 before | Expand all | Expand 10 after 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...) Expand all 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...) Expand 10 before | Expand all | Expand 10 after 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...) Expand all 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...) Expand 10 before | Expand all | Expand 10 after 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...) Expand all 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...) Expand 10 before | Expand all | Expand 10 after 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 |