1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
33 #include "src/base/platform/condition-variable.h"
34 #include "src/base/platform/platform.h"
35 #include "src/compilation-cache.h"
36 #include "src/debug.h"
37 #include "src/deoptimizer.h"
38 #include "src/frames.h"
39 #include "src/utils.h"
40 #include "test/cctest/cctest.h"
43 using ::v8::base::Mutex;
44 using ::v8::base::LockGuard;
45 using ::v8::base::ConditionVariable;
47 using ::v8::base::Semaphore;
48 using ::v8::internal::EmbeddedVector;
49 using ::v8::internal::Object;
50 using ::v8::internal::Handle;
51 using ::v8::internal::Heap;
52 using ::v8::internal::JSGlobalProxy;
53 using ::v8::internal::Code;
54 using ::v8::internal::Debug;
55 using ::v8::internal::Debugger;
56 using ::v8::internal::CommandMessage;
57 using ::v8::internal::CommandMessageQueue;
58 using ::v8::internal::StackFrame;
59 using ::v8::internal::StepAction;
60 using ::v8::internal::StepIn; // From StepAction enum
61 using ::v8::internal::StepNext; // From StepAction enum
62 using ::v8::internal::StepOut; // From StepAction enum
63 using ::v8::internal::Vector;
64 using ::v8::internal::StrLength;
66 // Size of temp buffer for formatting small strings.
67 #define SMALL_STRING_BUFFER_SIZE 80
69 // --- H e l p e r C l a s s e s
72 // Helper class for creating a V8 enviromnent for running tests
73 class DebugLocalContext {
75 inline DebugLocalContext(
76 v8::Isolate* isolate, v8::ExtensionConfiguration* extensions = 0,
77 v8::Handle<v8::ObjectTemplate> global_template =
78 v8::Handle<v8::ObjectTemplate>(),
79 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>())
81 context_(v8::Context::New(isolate, extensions, global_template,
85 inline DebugLocalContext(
86 v8::ExtensionConfiguration* extensions = 0,
87 v8::Handle<v8::ObjectTemplate> global_template =
88 v8::Handle<v8::ObjectTemplate>(),
89 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>())
90 : scope_(CcTest::isolate()),
91 context_(v8::Context::New(CcTest::isolate(), extensions,
92 global_template, global_object)) {
95 inline ~DebugLocalContext() {
98 inline v8::Local<v8::Context> context() { return context_; }
99 inline v8::Context* operator->() { return *context_; }
100 inline v8::Context* operator*() { return *context_; }
101 inline v8::Isolate* GetIsolate() { return context_->GetIsolate(); }
102 inline bool IsReady() { return !context_.IsEmpty(); }
104 v8::internal::Isolate* isolate =
105 reinterpret_cast<v8::internal::Isolate*>(context_->GetIsolate());
106 v8::internal::Factory* factory = isolate->factory();
107 // Expose the debug context global object in the global object for testing.
108 CHECK(isolate->debug()->Load());
109 Handle<v8::internal::Context> debug_context =
110 isolate->debug()->debug_context();
111 debug_context->set_security_token(
112 v8::Utils::OpenHandle(*context_)->security_token());
114 Handle<JSGlobalProxy> global(Handle<JSGlobalProxy>::cast(
115 v8::Utils::OpenHandle(*context_->Global())));
116 Handle<v8::internal::String> debug_string =
117 factory->InternalizeOneByteString(STATIC_CHAR_VECTOR("debug"));
118 v8::internal::Runtime::DefineObjectProperty(global, debug_string,
119 handle(debug_context->global_proxy(), isolate), DONT_ENUM).Check();
123 v8::HandleScope scope_;
124 v8::Local<v8::Context> context_;
128 // --- H e l p e r F u n c t i o n s
131 // Compile and run the supplied source and return the fequested function.
132 static v8::Local<v8::Function> CompileFunction(DebugLocalContext* env,
134 const char* function_name) {
135 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), source))
137 return v8::Local<v8::Function>::Cast((*env)->Global()->Get(
138 v8::String::NewFromUtf8(env->GetIsolate(), function_name)));
142 // Compile and run the supplied source and return the requested function.
143 static v8::Local<v8::Function> CompileFunction(v8::Isolate* isolate,
145 const char* function_name) {
146 v8::Script::Compile(v8::String::NewFromUtf8(isolate, source))->Run();
147 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global();
148 return v8::Local<v8::Function>::Cast(
149 global->Get(v8::String::NewFromUtf8(isolate, function_name)));
153 // Is there any debug info for the function?
154 static bool HasDebugInfo(v8::Handle<v8::Function> fun) {
155 Handle<v8::internal::JSFunction> f = v8::Utils::OpenHandle(*fun);
156 Handle<v8::internal::SharedFunctionInfo> shared(f->shared());
157 return Debug::HasDebugInfo(shared);
161 // Set a break point in a function and return the associated break point
163 static int SetBreakPoint(Handle<v8::internal::JSFunction> fun, int position) {
164 static int break_point = 0;
165 v8::internal::Isolate* isolate = fun->GetIsolate();
166 v8::internal::Debug* debug = isolate->debug();
167 debug->SetBreakPoint(
169 Handle<Object>(v8::internal::Smi::FromInt(++break_point), isolate),
175 // Set a break point in a function and return the associated break point
177 static int SetBreakPoint(v8::Handle<v8::Function> fun, int position) {
178 return SetBreakPoint(v8::Utils::OpenHandle(*fun), position);
182 // Set a break point in a function using the Debug object and return the
183 // associated break point number.
184 static int SetBreakPointFromJS(v8::Isolate* isolate,
185 const char* function_name,
186 int line, int position) {
187 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
189 "debug.Debug.setBreakPoint(%s,%d,%d)",
190 function_name, line, position);
191 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
192 v8::Handle<v8::String> str = v8::String::NewFromUtf8(isolate, buffer.start());
193 return v8::Script::Compile(str)->Run()->Int32Value();
197 // Set a break point in a script identified by id using the global Debug object.
198 static int SetScriptBreakPointByIdFromJS(v8::Isolate* isolate, int script_id,
199 int line, int column) {
200 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
202 // Column specified set script break point on precise location.
204 "debug.Debug.setScriptBreakPointById(%d,%d,%d)",
205 script_id, line, column);
207 // Column not specified set script break point on line.
209 "debug.Debug.setScriptBreakPointById(%d,%d)",
212 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
214 v8::TryCatch try_catch;
215 v8::Handle<v8::String> str =
216 v8::String::NewFromUtf8(isolate, buffer.start());
217 v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run();
218 CHECK(!try_catch.HasCaught());
219 return value->Int32Value();
224 // Set a break point in a script identified by name using the global Debug
226 static int SetScriptBreakPointByNameFromJS(v8::Isolate* isolate,
227 const char* script_name, int line,
229 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
231 // Column specified set script break point on precise location.
233 "debug.Debug.setScriptBreakPointByName(\"%s\",%d,%d)",
234 script_name, line, column);
236 // Column not specified set script break point on line.
238 "debug.Debug.setScriptBreakPointByName(\"%s\",%d)",
241 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
243 v8::TryCatch try_catch;
244 v8::Handle<v8::String> str =
245 v8::String::NewFromUtf8(isolate, buffer.start());
246 v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run();
247 CHECK(!try_catch.HasCaught());
248 return value->Int32Value();
253 // Clear a break point.
254 static void ClearBreakPoint(int break_point) {
255 v8::internal::Isolate* isolate = CcTest::i_isolate();
256 v8::internal::Debug* debug = isolate->debug();
257 debug->ClearBreakPoint(
258 Handle<Object>(v8::internal::Smi::FromInt(break_point), isolate));
262 // Clear a break point using the global Debug object.
263 static void ClearBreakPointFromJS(v8::Isolate* isolate,
264 int break_point_number) {
265 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
267 "debug.Debug.clearBreakPoint(%d)",
269 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
270 v8::Script::Compile(v8::String::NewFromUtf8(isolate, buffer.start()))->Run();
274 static void EnableScriptBreakPointFromJS(v8::Isolate* isolate,
275 int break_point_number) {
276 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
278 "debug.Debug.enableScriptBreakPoint(%d)",
280 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
281 v8::Script::Compile(v8::String::NewFromUtf8(isolate, buffer.start()))->Run();
285 static void DisableScriptBreakPointFromJS(v8::Isolate* isolate,
286 int break_point_number) {
287 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
289 "debug.Debug.disableScriptBreakPoint(%d)",
291 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
292 v8::Script::Compile(v8::String::NewFromUtf8(isolate, buffer.start()))->Run();
296 static void ChangeScriptBreakPointConditionFromJS(v8::Isolate* isolate,
297 int break_point_number,
298 const char* condition) {
299 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
301 "debug.Debug.changeScriptBreakPointCondition(%d, \"%s\")",
302 break_point_number, condition);
303 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
304 v8::Script::Compile(v8::String::NewFromUtf8(isolate, buffer.start()))->Run();
308 static void ChangeScriptBreakPointIgnoreCountFromJS(v8::Isolate* isolate,
309 int break_point_number,
311 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
313 "debug.Debug.changeScriptBreakPointIgnoreCount(%d, %d)",
314 break_point_number, ignoreCount);
315 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
316 v8::Script::Compile(v8::String::NewFromUtf8(isolate, buffer.start()))->Run();
320 // Change break on exception.
321 static void ChangeBreakOnException(bool caught, bool uncaught) {
322 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
323 debug->ChangeBreakOnException(v8::internal::BreakException, caught);
324 debug->ChangeBreakOnException(v8::internal::BreakUncaughtException, uncaught);
328 // Change break on exception using the global Debug object.
329 static void ChangeBreakOnExceptionFromJS(v8::Isolate* isolate, bool caught,
333 v8::String::NewFromUtf8(isolate, "debug.Debug.setBreakOnException()"))
337 v8::String::NewFromUtf8(isolate, "debug.Debug.clearBreakOnException()"))
342 v8::String::NewFromUtf8(
343 isolate, "debug.Debug.setBreakOnUncaughtException()"))->Run();
346 v8::String::NewFromUtf8(
347 isolate, "debug.Debug.clearBreakOnUncaughtException()"))->Run();
352 // Prepare to step to next break location.
353 static void PrepareStep(StepAction step_action) {
354 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
355 debug->PrepareStep(step_action, 1, StackFrame::NO_ID);
359 // This function is in namespace v8::internal to be friend with class
360 // v8::internal::Debug.
364 // Collect the currently debugged functions.
365 Handle<FixedArray> GetDebuggedFunctions() {
366 Debug* debug = CcTest::i_isolate()->debug();
368 v8::internal::DebugInfoListNode* node = debug->debug_info_list_;
370 // Find the number of debugged functions.
377 // Allocate array for the debugged functions
378 Handle<FixedArray> debugged_functions =
379 CcTest::i_isolate()->factory()->NewFixedArray(count);
381 // Run through the debug info objects and collect all functions.
384 debugged_functions->set(count++, *node->debug_info());
388 return debugged_functions;
392 // Check that the debugger has been fully unloaded.
393 void CheckDebuggerUnloaded(bool check_functions) {
394 // Check that the debugger context is cleared and that there is no debug
395 // information stored for the debugger.
396 CHECK(CcTest::i_isolate()->debug()->debug_context().is_null());
397 CHECK_EQ(NULL, CcTest::i_isolate()->debug()->debug_info_list_);
399 // Collect garbage to ensure weak handles are cleared.
400 CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
401 CcTest::heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
403 // Iterate the head and check that there are no debugger related objects left.
404 HeapIterator iterator(CcTest::heap());
405 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
406 CHECK(!obj->IsDebugInfo());
407 CHECK(!obj->IsBreakPointInfo());
409 // If deep check of functions is requested check that no debug break code
410 // is left in all functions.
411 if (check_functions) {
412 if (obj->IsJSFunction()) {
413 JSFunction* fun = JSFunction::cast(obj);
414 for (RelocIterator it(fun->shared()->code()); !it.done(); it.next()) {
415 RelocInfo::Mode rmode = it.rinfo()->rmode();
416 if (RelocInfo::IsCodeTarget(rmode)) {
417 CHECK(!Debug::IsDebugBreak(it.rinfo()->target_address()));
418 } else if (RelocInfo::IsJSReturn(rmode)) {
419 CHECK(!Debug::IsDebugBreakAtReturn(it.rinfo()));
428 } } // namespace v8::internal
431 // Check that the debugger has been fully unloaded.
432 static void CheckDebuggerUnloaded(bool check_functions = false) {
433 // Let debugger to unload itself synchronously
434 v8::Debug::ProcessDebugMessages();
436 v8::internal::CheckDebuggerUnloaded(check_functions);
440 // Inherit from BreakLocationIterator to get access to protected parts for
442 class TestBreakLocationIterator: public v8::internal::BreakLocationIterator {
444 explicit TestBreakLocationIterator(Handle<v8::internal::DebugInfo> debug_info)
445 : BreakLocationIterator(debug_info, v8::internal::SOURCE_BREAK_LOCATIONS) {}
446 v8::internal::RelocIterator* it() { return reloc_iterator_; }
447 v8::internal::RelocIterator* it_original() {
448 return reloc_iterator_original_;
453 // Compile a function, set a break point and check that the call at the break
454 // location in the code is the expected debug_break function.
455 void CheckDebugBreakFunction(DebugLocalContext* env,
456 const char* source, const char* name,
457 int position, v8::internal::RelocInfo::Mode mode,
459 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
461 // Create function and set the break point.
462 Handle<v8::internal::JSFunction> fun = v8::Utils::OpenHandle(
463 *CompileFunction(env, source, name));
464 int bp = SetBreakPoint(fun, position);
466 // Check that the debug break function is as expected.
467 Handle<v8::internal::SharedFunctionInfo> shared(fun->shared());
468 CHECK(Debug::HasDebugInfo(shared));
469 TestBreakLocationIterator it1(Debug::GetDebugInfo(shared));
470 it1.FindBreakLocationFromPosition(position, v8::internal::STATEMENT_ALIGNED);
471 v8::internal::RelocInfo::Mode actual_mode = it1.it()->rinfo()->rmode();
472 if (actual_mode == v8::internal::RelocInfo::CODE_TARGET_WITH_ID) {
473 actual_mode = v8::internal::RelocInfo::CODE_TARGET;
475 CHECK_EQ(mode, actual_mode);
476 if (mode != v8::internal::RelocInfo::JS_RETURN) {
477 CHECK_EQ(debug_break,
478 Code::GetCodeFromTargetAddress(it1.it()->rinfo()->target_address()));
480 CHECK(Debug::IsDebugBreakAtReturn(it1.it()->rinfo()));
483 // Clear the break point and check that the debug break function is no longer
486 CHECK(!debug->HasDebugInfo(shared));
487 CHECK(debug->EnsureDebugInfo(shared, fun));
488 TestBreakLocationIterator it2(Debug::GetDebugInfo(shared));
489 it2.FindBreakLocationFromPosition(position, v8::internal::STATEMENT_ALIGNED);
490 actual_mode = it2.it()->rinfo()->rmode();
491 if (actual_mode == v8::internal::RelocInfo::CODE_TARGET_WITH_ID) {
492 actual_mode = v8::internal::RelocInfo::CODE_TARGET;
494 CHECK_EQ(mode, actual_mode);
495 if (mode == v8::internal::RelocInfo::JS_RETURN) {
496 CHECK(!Debug::IsDebugBreakAtReturn(it2.it()->rinfo()));
501 // --- D e b u g E v e n t H a n d l e r s
503 // --- The different tests uses a number of debug event handlers.
507 // Source for the JavaScript function which picks out the function
509 const char* frame_function_name_source =
510 "function frame_function_name(exec_state, frame_number) {"
511 " return exec_state.frame(frame_number).func().name();"
513 v8::Local<v8::Function> frame_function_name;
516 // Source for the JavaScript function which pick out the name of the
517 // first argument of a frame.
518 const char* frame_argument_name_source =
519 "function frame_argument_name(exec_state, frame_number) {"
520 " return exec_state.frame(frame_number).argumentName(0);"
522 v8::Local<v8::Function> frame_argument_name;
525 // Source for the JavaScript function which pick out the value of the
526 // first argument of a frame.
527 const char* frame_argument_value_source =
528 "function frame_argument_value(exec_state, frame_number) {"
529 " return exec_state.frame(frame_number).argumentValue(0).value_;"
531 v8::Local<v8::Function> frame_argument_value;
534 // Source for the JavaScript function which pick out the name of the
535 // first argument of a frame.
536 const char* frame_local_name_source =
537 "function frame_local_name(exec_state, frame_number) {"
538 " return exec_state.frame(frame_number).localName(0);"
540 v8::Local<v8::Function> frame_local_name;
543 // Source for the JavaScript function which pick out the value of the
544 // first argument of a frame.
545 const char* frame_local_value_source =
546 "function frame_local_value(exec_state, frame_number) {"
547 " return exec_state.frame(frame_number).localValue(0).value_;"
549 v8::Local<v8::Function> frame_local_value;
552 // Source for the JavaScript function which picks out the source line for the
554 const char* frame_source_line_source =
555 "function frame_source_line(exec_state) {"
556 " return exec_state.frame(0).sourceLine();"
558 v8::Local<v8::Function> frame_source_line;
561 // Source for the JavaScript function which picks out the source column for the
563 const char* frame_source_column_source =
564 "function frame_source_column(exec_state) {"
565 " return exec_state.frame(0).sourceColumn();"
567 v8::Local<v8::Function> frame_source_column;
570 // Source for the JavaScript function which picks out the script name for the
572 const char* frame_script_name_source =
573 "function frame_script_name(exec_state) {"
574 " return exec_state.frame(0).func().script().name();"
576 v8::Local<v8::Function> frame_script_name;
579 // Source for the JavaScript function which returns the number of frames.
580 static const char* frame_count_source =
581 "function frame_count(exec_state) {"
582 " return exec_state.frameCount();"
584 v8::Handle<v8::Function> frame_count;
587 // Global variable to store the last function hit - used by some tests.
588 char last_function_hit[80];
590 // Global variable to store the name for last script hit - used by some tests.
591 char last_script_name_hit[80];
593 // Global variables to store the last source position - used by some tests.
594 int last_source_line = -1;
595 int last_source_column = -1;
597 // Debug event handler which counts the break points which have been hit.
598 int break_point_hit_count = 0;
599 int break_point_hit_count_deoptimize = 0;
600 static void DebugEventBreakPointHitCount(
601 const v8::Debug::EventDetails& event_details) {
602 v8::DebugEvent event = event_details.GetEvent();
603 v8::Handle<v8::Object> exec_state = event_details.GetExecutionState();
604 v8::internal::Isolate* isolate = CcTest::i_isolate();
605 Debug* debug = isolate->debug();
606 // When hitting a debug event listener there must be a break set.
607 CHECK_NE(debug->break_id(), 0);
609 // Count the number of breaks.
610 if (event == v8::Break) {
611 break_point_hit_count++;
612 if (!frame_function_name.IsEmpty()) {
613 // Get the name of the function.
615 v8::Handle<v8::Value> argv[argc] = {
616 exec_state, v8::Integer::New(CcTest::isolate(), 0)
618 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
620 if (result->IsUndefined()) {
621 last_function_hit[0] = '\0';
623 CHECK(result->IsString());
624 v8::Handle<v8::String> function_name(result->ToString());
625 function_name->WriteUtf8(last_function_hit);
629 if (!frame_source_line.IsEmpty()) {
630 // Get the source line.
632 v8::Handle<v8::Value> argv[argc] = { exec_state };
633 v8::Handle<v8::Value> result = frame_source_line->Call(exec_state,
635 CHECK(result->IsNumber());
636 last_source_line = result->Int32Value();
639 if (!frame_source_column.IsEmpty()) {
640 // Get the source column.
642 v8::Handle<v8::Value> argv[argc] = { exec_state };
643 v8::Handle<v8::Value> result = frame_source_column->Call(exec_state,
645 CHECK(result->IsNumber());
646 last_source_column = result->Int32Value();
649 if (!frame_script_name.IsEmpty()) {
650 // Get the script name of the function script.
652 v8::Handle<v8::Value> argv[argc] = { exec_state };
653 v8::Handle<v8::Value> result = frame_script_name->Call(exec_state,
655 if (result->IsUndefined()) {
656 last_script_name_hit[0] = '\0';
658 CHECK(result->IsString());
659 v8::Handle<v8::String> script_name(result->ToString());
660 script_name->WriteUtf8(last_script_name_hit);
664 // Perform a full deoptimization when the specified number of
665 // breaks have been hit.
666 if (break_point_hit_count == break_point_hit_count_deoptimize) {
667 i::Deoptimizer::DeoptimizeAll(isolate);
673 // Debug event handler which counts a number of events and collects the stack
674 // height if there is a function compiled for that.
675 int exception_hit_count = 0;
676 int uncaught_exception_hit_count = 0;
677 int last_js_stack_height = -1;
678 v8::Handle<v8::Function> debug_event_listener_callback;
679 int debug_event_listener_callback_result;
681 static void DebugEventCounterClear() {
682 break_point_hit_count = 0;
683 exception_hit_count = 0;
684 uncaught_exception_hit_count = 0;
687 static void DebugEventCounter(
688 const v8::Debug::EventDetails& event_details) {
689 v8::DebugEvent event = event_details.GetEvent();
690 v8::Handle<v8::Object> exec_state = event_details.GetExecutionState();
691 v8::Handle<v8::Object> event_data = event_details.GetEventData();
692 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
694 // When hitting a debug event listener there must be a break set.
695 CHECK_NE(debug->break_id(), 0);
697 // Count the number of breaks.
698 if (event == v8::Break) {
699 break_point_hit_count++;
700 } else if (event == v8::Exception) {
701 exception_hit_count++;
703 // Check whether the exception was uncaught.
704 v8::Local<v8::String> fun_name =
705 v8::String::NewFromUtf8(CcTest::isolate(), "uncaught");
706 v8::Local<v8::Function> fun =
707 v8::Local<v8::Function>::Cast(event_data->Get(fun_name));
708 v8::Local<v8::Value> result = fun->Call(event_data, 0, NULL);
709 if (result->IsTrue()) {
710 uncaught_exception_hit_count++;
714 // Collect the JavsScript stack height if the function frame_count is
716 if (!frame_count.IsEmpty()) {
717 static const int kArgc = 1;
718 v8::Handle<v8::Value> argv[kArgc] = { exec_state };
719 // Using exec_state as receiver is just to have a receiver.
720 v8::Handle<v8::Value> result = frame_count->Call(exec_state, kArgc, argv);
721 last_js_stack_height = result->Int32Value();
724 // Run callback from DebugEventListener and check the result.
725 if (!debug_event_listener_callback.IsEmpty()) {
726 v8::Handle<v8::Value> result =
727 debug_event_listener_callback->Call(event_data, 0, NULL);
728 CHECK(!result.IsEmpty());
729 CHECK_EQ(debug_event_listener_callback_result, result->Int32Value());
734 // Debug event handler which evaluates a number of expressions when a break
735 // point is hit. Each evaluated expression is compared with an expected value.
736 // For this debug event handler to work the following two global varaibles
737 // must be initialized.
738 // checks: An array of expressions and expected results
739 // evaluate_check_function: A JavaScript function (see below)
741 // Structure for holding checks to do.
742 struct EvaluateCheck {
743 const char* expr; // An expression to evaluate when a break point is hit.
744 v8::Handle<v8::Value> expected; // The expected result.
748 // Array of checks to do.
749 struct EvaluateCheck* checks = NULL;
750 // Source for The JavaScript function which can do the evaluation when a break
752 const char* evaluate_check_source =
753 "function evaluate_check(exec_state, expr, expected) {"
754 " return exec_state.frame(0).evaluate(expr).value() === expected;"
756 v8::Local<v8::Function> evaluate_check_function;
758 // The actual debug event described by the longer comment above.
759 static void DebugEventEvaluate(
760 const v8::Debug::EventDetails& event_details) {
761 v8::DebugEvent event = event_details.GetEvent();
762 v8::Handle<v8::Object> exec_state = event_details.GetExecutionState();
763 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
764 // When hitting a debug event listener there must be a break set.
765 CHECK_NE(debug->break_id(), 0);
767 if (event == v8::Break) {
768 break_point_hit_count++;
769 for (int i = 0; checks[i].expr != NULL; i++) {
771 v8::Handle<v8::Value> argv[argc] = {
773 v8::String::NewFromUtf8(CcTest::isolate(), checks[i].expr),
775 v8::Handle<v8::Value> result =
776 evaluate_check_function->Call(exec_state, argc, argv);
777 if (!result->IsTrue()) {
778 v8::String::Utf8Value utf8(checks[i].expected->ToString());
779 V8_Fatal(__FILE__, __LINE__, "%s != %s", checks[i].expr, *utf8);
786 // This debug event listener removes a breakpoint in a function
787 int debug_event_remove_break_point = 0;
788 static void DebugEventRemoveBreakPoint(
789 const v8::Debug::EventDetails& event_details) {
790 v8::DebugEvent event = event_details.GetEvent();
791 v8::Handle<v8::Value> data = event_details.GetCallbackData();
792 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
793 // When hitting a debug event listener there must be a break set.
794 CHECK_NE(debug->break_id(), 0);
796 if (event == v8::Break) {
797 break_point_hit_count++;
798 CHECK(data->IsFunction());
799 ClearBreakPoint(debug_event_remove_break_point);
804 // Debug event handler which counts break points hit and performs a step
806 StepAction step_action = StepIn; // Step action to perform when stepping.
807 static void DebugEventStep(
808 const v8::Debug::EventDetails& event_details) {
809 v8::DebugEvent event = event_details.GetEvent();
810 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
811 // When hitting a debug event listener there must be a break set.
812 CHECK_NE(debug->break_id(), 0);
814 if (event == v8::Break) {
815 break_point_hit_count++;
816 PrepareStep(step_action);
821 // Debug event handler which counts break points hit and performs a step
822 // afterwards. For each call the expected function is checked.
823 // For this debug event handler to work the following two global varaibles
824 // must be initialized.
825 // expected_step_sequence: An array of the expected function call sequence.
826 // frame_function_name: A JavaScript function (see below).
828 // String containing the expected function call sequence. Note: this only works
829 // if functions have name length of one.
830 const char* expected_step_sequence = NULL;
832 // The actual debug event described by the longer comment above.
833 static void DebugEventStepSequence(
834 const v8::Debug::EventDetails& event_details) {
835 v8::DebugEvent event = event_details.GetEvent();
836 v8::Handle<v8::Object> exec_state = event_details.GetExecutionState();
837 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
838 // When hitting a debug event listener there must be a break set.
839 CHECK_NE(debug->break_id(), 0);
841 if (event == v8::Break || event == v8::Exception) {
842 // Check that the current function is the expected.
843 CHECK(break_point_hit_count <
844 StrLength(expected_step_sequence));
846 v8::Handle<v8::Value> argv[argc] = {
847 exec_state, v8::Integer::New(CcTest::isolate(), 0)
849 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
851 CHECK(result->IsString());
852 v8::String::Utf8Value function_name(result->ToString());
853 CHECK_EQ(1, StrLength(*function_name));
854 CHECK_EQ((*function_name)[0],
855 expected_step_sequence[break_point_hit_count]);
858 break_point_hit_count++;
859 PrepareStep(step_action);
864 // Debug event handler which performs a garbage collection.
865 static void DebugEventBreakPointCollectGarbage(
866 const v8::Debug::EventDetails& event_details) {
867 v8::DebugEvent event = event_details.GetEvent();
868 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
869 // When hitting a debug event listener there must be a break set.
870 CHECK_NE(debug->break_id(), 0);
872 // Perform a garbage collection when break point is hit and continue. Based
873 // on the number of break points hit either scavenge or mark compact
874 // collector is used.
875 if (event == v8::Break) {
876 break_point_hit_count++;
877 if (break_point_hit_count % 2 == 0) {
879 CcTest::heap()->CollectGarbage(v8::internal::NEW_SPACE);
881 // Mark sweep compact.
882 CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
888 // Debug event handler which re-issues a debug break and calls the garbage
889 // collector to have the heap verified.
890 static void DebugEventBreak(
891 const v8::Debug::EventDetails& event_details) {
892 v8::DebugEvent event = event_details.GetEvent();
893 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
894 // When hitting a debug event listener there must be a break set.
895 CHECK_NE(debug->break_id(), 0);
897 if (event == v8::Break) {
898 // Count the number of breaks.
899 break_point_hit_count++;
901 // Run the garbage collector to enforce heap verification if option
902 // --verify-heap is set.
903 CcTest::heap()->CollectGarbage(v8::internal::NEW_SPACE);
905 // Set the break flag again to come back here as soon as possible.
906 v8::Debug::DebugBreak(CcTest::isolate());
911 // Debug event handler which re-issues a debug break until a limit has been
913 int max_break_point_hit_count = 0;
914 bool terminate_after_max_break_point_hit = false;
915 static void DebugEventBreakMax(
916 const v8::Debug::EventDetails& event_details) {
917 v8::DebugEvent event = event_details.GetEvent();
918 v8::Handle<v8::Object> exec_state = event_details.GetExecutionState();
919 v8::Isolate* v8_isolate = CcTest::isolate();
920 v8::internal::Isolate* isolate = CcTest::i_isolate();
921 v8::internal::Debug* debug = isolate->debug();
922 // When hitting a debug event listener there must be a break set.
923 CHECK_NE(debug->break_id(), 0);
925 if (event == v8::Break) {
926 if (break_point_hit_count < max_break_point_hit_count) {
927 // Count the number of breaks.
928 break_point_hit_count++;
930 // Collect the JavsScript stack height if the function frame_count is
932 if (!frame_count.IsEmpty()) {
933 static const int kArgc = 1;
934 v8::Handle<v8::Value> argv[kArgc] = { exec_state };
935 // Using exec_state as receiver is just to have a receiver.
936 v8::Handle<v8::Value> result =
937 frame_count->Call(exec_state, kArgc, argv);
938 last_js_stack_height = result->Int32Value();
941 // Set the break flag again to come back here as soon as possible.
942 v8::Debug::DebugBreak(v8_isolate);
944 } else if (terminate_after_max_break_point_hit) {
945 // Terminate execution after the last break if requested.
946 v8::V8::TerminateExecution(v8_isolate);
949 // Perform a full deoptimization when the specified number of
950 // breaks have been hit.
951 if (break_point_hit_count == break_point_hit_count_deoptimize) {
952 i::Deoptimizer::DeoptimizeAll(isolate);
958 // --- M e s s a g e C a l l b a c k
961 // Message callback which counts the number of messages.
962 int message_callback_count = 0;
964 static void MessageCallbackCountClear() {
965 message_callback_count = 0;
968 static void MessageCallbackCount(v8::Handle<v8::Message> message,
969 v8::Handle<v8::Value> data) {
970 message_callback_count++;
974 // --- T h e A c t u a l T e s t s
977 // Test that the debug break function is the expected one for different kinds
978 // of break locations.
980 using ::v8::internal::Builtins;
981 using ::v8::internal::Isolate;
982 DebugLocalContext env;
983 v8::HandleScope scope(env->GetIsolate());
985 CheckDebugBreakFunction(&env,
986 "function f1(){}", "f1",
988 v8::internal::RelocInfo::JS_RETURN,
990 CheckDebugBreakFunction(&env,
991 "function f2(){x=1;}", "f2",
993 v8::internal::RelocInfo::CODE_TARGET,
994 CcTest::i_isolate()->builtins()->builtin(
995 Builtins::kStoreIC_DebugBreak));
996 CheckDebugBreakFunction(&env,
997 "function f3(){var a=x;}", "f3",
999 v8::internal::RelocInfo::CODE_TARGET,
1000 CcTest::i_isolate()->builtins()->builtin(
1001 Builtins::kLoadIC_DebugBreak));
1003 // TODO(1240753): Make the test architecture independent or split
1004 // parts of the debugger into architecture dependent files. This
1005 // part currently disabled as it is not portable between IA32/ARM.
1006 // Currently on ICs for keyed store/load on ARM.
1007 #if !defined (__arm__) && !defined(__thumb__)
1008 CheckDebugBreakFunction(
1010 "function f4(){var index='propertyName'; var a={}; a[index] = 'x';}",
1013 v8::internal::RelocInfo::CODE_TARGET,
1014 CcTest::i_isolate()->builtins()->builtin(
1015 Builtins::kKeyedStoreIC_DebugBreak));
1016 CheckDebugBreakFunction(
1018 "function f5(){var index='propertyName'; var a={}; return a[index];}",
1021 v8::internal::RelocInfo::CODE_TARGET,
1022 CcTest::i_isolate()->builtins()->builtin(
1023 Builtins::kKeyedLoadIC_DebugBreak));
1026 CheckDebugBreakFunction(
1028 "function f6(a){return a==null;}",
1031 v8::internal::RelocInfo::CODE_TARGET,
1032 CcTest::i_isolate()->builtins()->builtin(
1033 Builtins::kCompareNilIC_DebugBreak));
1035 // Check the debug break code stubs for call ICs with different number of
1037 // TODO(verwaest): XXX update test.
1038 // Handle<Code> debug_break_0 = v8::internal::ComputeCallDebugBreak(0);
1039 // Handle<Code> debug_break_1 = v8::internal::ComputeCallDebugBreak(1);
1040 // Handle<Code> debug_break_4 = v8::internal::ComputeCallDebugBreak(4);
1042 // CheckDebugBreakFunction(&env,
1043 // "function f4_0(){x();}", "f4_0",
1045 // v8::internal::RelocInfo::CODE_TARGET,
1048 // CheckDebugBreakFunction(&env,
1049 // "function f4_1(){x(1);}", "f4_1",
1051 // v8::internal::RelocInfo::CODE_TARGET,
1054 // CheckDebugBreakFunction(&env,
1055 // "function f4_4(){x(1,2,3,4);}", "f4_4",
1057 // v8::internal::RelocInfo::CODE_TARGET,
1062 // Test that the debug info in the VM is in sync with the functions being
1065 DebugLocalContext env;
1066 v8::HandleScope scope(env->GetIsolate());
1067 // Create a couple of functions for the test.
1068 v8::Local<v8::Function> foo =
1069 CompileFunction(&env, "function foo(){}", "foo");
1070 v8::Local<v8::Function> bar =
1071 CompileFunction(&env, "function bar(){}", "bar");
1072 // Initially no functions are debugged.
1073 CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
1074 CHECK(!HasDebugInfo(foo));
1075 CHECK(!HasDebugInfo(bar));
1076 // One function (foo) is debugged.
1077 int bp1 = SetBreakPoint(foo, 0);
1078 CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
1079 CHECK(HasDebugInfo(foo));
1080 CHECK(!HasDebugInfo(bar));
1081 // Two functions are debugged.
1082 int bp2 = SetBreakPoint(bar, 0);
1083 CHECK_EQ(2, v8::internal::GetDebuggedFunctions()->length());
1084 CHECK(HasDebugInfo(foo));
1085 CHECK(HasDebugInfo(bar));
1086 // One function (bar) is debugged.
1087 ClearBreakPoint(bp1);
1088 CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
1089 CHECK(!HasDebugInfo(foo));
1090 CHECK(HasDebugInfo(bar));
1091 // No functions are debugged.
1092 ClearBreakPoint(bp2);
1093 CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
1094 CHECK(!HasDebugInfo(foo));
1095 CHECK(!HasDebugInfo(bar));
1099 // Test that a break point can be set at an IC store location.
1100 TEST(BreakPointICStore) {
1101 break_point_hit_count = 0;
1102 DebugLocalContext env;
1103 v8::HandleScope scope(env->GetIsolate());
1105 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1106 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
1107 "function foo(){bar=0;}"))->Run();
1108 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
1109 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo")));
1111 // Run without breakpoints.
1112 foo->Call(env->Global(), 0, NULL);
1113 CHECK_EQ(0, break_point_hit_count);
1115 // Run with breakpoint
1116 int bp = SetBreakPoint(foo, 0);
1117 foo->Call(env->Global(), 0, NULL);
1118 CHECK_EQ(1, break_point_hit_count);
1119 foo->Call(env->Global(), 0, NULL);
1120 CHECK_EQ(2, break_point_hit_count);
1122 // Run without breakpoints.
1123 ClearBreakPoint(bp);
1124 foo->Call(env->Global(), 0, NULL);
1125 CHECK_EQ(2, break_point_hit_count);
1127 v8::Debug::SetDebugEventListener(NULL);
1128 CheckDebuggerUnloaded();
1132 // Test that a break point can be set at an IC load location.
1133 TEST(BreakPointICLoad) {
1134 break_point_hit_count = 0;
1135 DebugLocalContext env;
1136 v8::HandleScope scope(env->GetIsolate());
1137 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1138 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "bar=1"))
1140 v8::Script::Compile(
1141 v8::String::NewFromUtf8(env->GetIsolate(), "function foo(){var x=bar;}"))
1143 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
1144 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo")));
1146 // Run without breakpoints.
1147 foo->Call(env->Global(), 0, NULL);
1148 CHECK_EQ(0, break_point_hit_count);
1150 // Run with breakpoint.
1151 int bp = SetBreakPoint(foo, 0);
1152 foo->Call(env->Global(), 0, NULL);
1153 CHECK_EQ(1, break_point_hit_count);
1154 foo->Call(env->Global(), 0, NULL);
1155 CHECK_EQ(2, break_point_hit_count);
1157 // Run without breakpoints.
1158 ClearBreakPoint(bp);
1159 foo->Call(env->Global(), 0, NULL);
1160 CHECK_EQ(2, break_point_hit_count);
1162 v8::Debug::SetDebugEventListener(NULL);
1163 CheckDebuggerUnloaded();
1167 // Test that a break point can be set at an IC call location.
1168 TEST(BreakPointICCall) {
1169 break_point_hit_count = 0;
1170 DebugLocalContext env;
1171 v8::HandleScope scope(env->GetIsolate());
1172 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1173 v8::Script::Compile(
1174 v8::String::NewFromUtf8(env->GetIsolate(), "function bar(){}"))->Run();
1175 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
1176 "function foo(){bar();}"))->Run();
1177 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
1178 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo")));
1180 // Run without breakpoints.
1181 foo->Call(env->Global(), 0, NULL);
1182 CHECK_EQ(0, break_point_hit_count);
1184 // Run with breakpoint
1185 int bp = SetBreakPoint(foo, 0);
1186 foo->Call(env->Global(), 0, NULL);
1187 CHECK_EQ(1, break_point_hit_count);
1188 foo->Call(env->Global(), 0, NULL);
1189 CHECK_EQ(2, break_point_hit_count);
1191 // Run without breakpoints.
1192 ClearBreakPoint(bp);
1193 foo->Call(env->Global(), 0, NULL);
1194 CHECK_EQ(2, break_point_hit_count);
1196 v8::Debug::SetDebugEventListener(NULL);
1197 CheckDebuggerUnloaded();
1201 // Test that a break point can be set at an IC call location and survive a GC.
1202 TEST(BreakPointICCallWithGC) {
1203 break_point_hit_count = 0;
1204 DebugLocalContext env;
1205 v8::HandleScope scope(env->GetIsolate());
1206 v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage);
1207 v8::Script::Compile(
1208 v8::String::NewFromUtf8(env->GetIsolate(), "function bar(){return 1;}"))
1210 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
1211 "function foo(){return bar();}"))
1213 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
1214 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo")));
1216 // Run without breakpoints.
1217 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1218 CHECK_EQ(0, break_point_hit_count);
1220 // Run with breakpoint.
1221 int bp = SetBreakPoint(foo, 0);
1222 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1223 CHECK_EQ(1, break_point_hit_count);
1224 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1225 CHECK_EQ(2, break_point_hit_count);
1227 // Run without breakpoints.
1228 ClearBreakPoint(bp);
1229 foo->Call(env->Global(), 0, NULL);
1230 CHECK_EQ(2, break_point_hit_count);
1232 v8::Debug::SetDebugEventListener(NULL);
1233 CheckDebuggerUnloaded();
1237 // Test that a break point can be set at an IC call location and survive a GC.
1238 TEST(BreakPointConstructCallWithGC) {
1239 break_point_hit_count = 0;
1240 DebugLocalContext env;
1241 v8::HandleScope scope(env->GetIsolate());
1242 v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage);
1243 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
1244 "function bar(){ this.x = 1;}"))
1246 v8::Script::Compile(
1247 v8::String::NewFromUtf8(env->GetIsolate(),
1248 "function foo(){return new bar(1).x;}"))->Run();
1249 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
1250 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo")));
1252 // Run without breakpoints.
1253 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1254 CHECK_EQ(0, break_point_hit_count);
1256 // Run with breakpoint.
1257 int bp = SetBreakPoint(foo, 0);
1258 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1259 CHECK_EQ(1, break_point_hit_count);
1260 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1261 CHECK_EQ(2, break_point_hit_count);
1263 // Run without breakpoints.
1264 ClearBreakPoint(bp);
1265 foo->Call(env->Global(), 0, NULL);
1266 CHECK_EQ(2, break_point_hit_count);
1268 v8::Debug::SetDebugEventListener(NULL);
1269 CheckDebuggerUnloaded();
1273 // Test that a break point can be set at a return store location.
1274 TEST(BreakPointReturn) {
1275 break_point_hit_count = 0;
1276 DebugLocalContext env;
1277 v8::HandleScope scope(env->GetIsolate());
1279 // Create a functions for checking the source line and column when hitting
1281 frame_source_line = CompileFunction(&env,
1282 frame_source_line_source,
1283 "frame_source_line");
1284 frame_source_column = CompileFunction(&env,
1285 frame_source_column_source,
1286 "frame_source_column");
1289 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1290 v8::Script::Compile(
1291 v8::String::NewFromUtf8(env->GetIsolate(), "function foo(){}"))->Run();
1292 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
1293 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo")));
1295 // Run without breakpoints.
1296 foo->Call(env->Global(), 0, NULL);
1297 CHECK_EQ(0, break_point_hit_count);
1299 // Run with breakpoint
1300 int bp = SetBreakPoint(foo, 0);
1301 foo->Call(env->Global(), 0, NULL);
1302 CHECK_EQ(1, break_point_hit_count);
1303 CHECK_EQ(0, last_source_line);
1304 CHECK_EQ(15, last_source_column);
1305 foo->Call(env->Global(), 0, NULL);
1306 CHECK_EQ(2, break_point_hit_count);
1307 CHECK_EQ(0, last_source_line);
1308 CHECK_EQ(15, last_source_column);
1310 // Run without breakpoints.
1311 ClearBreakPoint(bp);
1312 foo->Call(env->Global(), 0, NULL);
1313 CHECK_EQ(2, break_point_hit_count);
1315 v8::Debug::SetDebugEventListener(NULL);
1316 CheckDebuggerUnloaded();
1320 static void CallWithBreakPoints(v8::Local<v8::Object> recv,
1321 v8::Local<v8::Function> f,
1322 int break_point_count,
1324 break_point_hit_count = 0;
1325 for (int i = 0; i < call_count; i++) {
1326 f->Call(recv, 0, NULL);
1327 CHECK_EQ((i + 1) * break_point_count, break_point_hit_count);
1332 // Test GC during break point processing.
1333 TEST(GCDuringBreakPointProcessing) {
1334 break_point_hit_count = 0;
1335 DebugLocalContext env;
1336 v8::HandleScope scope(env->GetIsolate());
1338 v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage);
1339 v8::Local<v8::Function> foo;
1341 // Test IC store break point with garbage collection.
1342 foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1343 SetBreakPoint(foo, 0);
1344 CallWithBreakPoints(env->Global(), foo, 1, 10);
1346 // Test IC load break point with garbage collection.
1347 foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1348 SetBreakPoint(foo, 0);
1349 CallWithBreakPoints(env->Global(), foo, 1, 10);
1351 // Test IC call break point with garbage collection.
1352 foo = CompileFunction(&env, "function bar(){};function foo(){bar();}", "foo");
1353 SetBreakPoint(foo, 0);
1354 CallWithBreakPoints(env->Global(), foo, 1, 10);
1356 // Test return break point with garbage collection.
1357 foo = CompileFunction(&env, "function foo(){}", "foo");
1358 SetBreakPoint(foo, 0);
1359 CallWithBreakPoints(env->Global(), foo, 1, 25);
1361 // Test debug break slot break point with garbage collection.
1362 foo = CompileFunction(&env, "function foo(){var a;}", "foo");
1363 SetBreakPoint(foo, 0);
1364 CallWithBreakPoints(env->Global(), foo, 1, 25);
1366 v8::Debug::SetDebugEventListener(NULL);
1367 CheckDebuggerUnloaded();
1371 // Call the function three times with different garbage collections in between
1372 // and make sure that the break point survives.
1373 static void CallAndGC(v8::Local<v8::Object> recv,
1374 v8::Local<v8::Function> f) {
1375 break_point_hit_count = 0;
1377 for (int i = 0; i < 3; i++) {
1379 f->Call(recv, 0, NULL);
1380 CHECK_EQ(1 + i * 3, break_point_hit_count);
1382 // Scavenge and call function.
1383 CcTest::heap()->CollectGarbage(v8::internal::NEW_SPACE);
1384 f->Call(recv, 0, NULL);
1385 CHECK_EQ(2 + i * 3, break_point_hit_count);
1387 // Mark sweep (and perhaps compact) and call function.
1388 CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
1389 f->Call(recv, 0, NULL);
1390 CHECK_EQ(3 + i * 3, break_point_hit_count);
1395 // Test that a break point can be set at a return store location.
1396 TEST(BreakPointSurviveGC) {
1397 break_point_hit_count = 0;
1398 DebugLocalContext env;
1399 v8::HandleScope scope(env->GetIsolate());
1401 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1402 v8::Local<v8::Function> foo;
1404 // Test IC store break point with garbage collection.
1406 CompileFunction(&env, "function foo(){}", "foo");
1407 foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1408 SetBreakPoint(foo, 0);
1410 CallAndGC(env->Global(), foo);
1412 // Test IC load break point with garbage collection.
1414 CompileFunction(&env, "function foo(){}", "foo");
1415 foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1416 SetBreakPoint(foo, 0);
1418 CallAndGC(env->Global(), foo);
1420 // Test IC call break point with garbage collection.
1422 CompileFunction(&env, "function foo(){}", "foo");
1423 foo = CompileFunction(&env,
1424 "function bar(){};function foo(){bar();}",
1426 SetBreakPoint(foo, 0);
1428 CallAndGC(env->Global(), foo);
1430 // Test return break point with garbage collection.
1432 CompileFunction(&env, "function foo(){}", "foo");
1433 foo = CompileFunction(&env, "function foo(){}", "foo");
1434 SetBreakPoint(foo, 0);
1436 CallAndGC(env->Global(), foo);
1438 // Test non IC break point with garbage collection.
1440 CompileFunction(&env, "function foo(){}", "foo");
1441 foo = CompileFunction(&env, "function foo(){var bar=0;}", "foo");
1442 SetBreakPoint(foo, 0);
1444 CallAndGC(env->Global(), foo);
1447 v8::Debug::SetDebugEventListener(NULL);
1448 CheckDebuggerUnloaded();
1452 // Test that break points can be set using the global Debug object.
1453 TEST(BreakPointThroughJavaScript) {
1454 break_point_hit_count = 0;
1455 DebugLocalContext env;
1456 v8::HandleScope scope(env->GetIsolate());
1459 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1460 v8::Script::Compile(
1461 v8::String::NewFromUtf8(env->GetIsolate(), "function bar(){}"))->Run();
1462 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
1463 "function foo(){bar();bar();}"))
1465 // 012345678901234567890
1467 // Break points are set at position 3 and 9
1468 v8::Local<v8::Script> foo =
1469 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "foo()"));
1471 // Run without breakpoints.
1473 CHECK_EQ(0, break_point_hit_count);
1475 // Run with one breakpoint
1476 int bp1 = SetBreakPointFromJS(env->GetIsolate(), "foo", 0, 3);
1478 CHECK_EQ(1, break_point_hit_count);
1480 CHECK_EQ(2, break_point_hit_count);
1482 // Run with two breakpoints
1483 int bp2 = SetBreakPointFromJS(env->GetIsolate(), "foo", 0, 9);
1485 CHECK_EQ(4, break_point_hit_count);
1487 CHECK_EQ(6, break_point_hit_count);
1489 // Run with one breakpoint
1490 ClearBreakPointFromJS(env->GetIsolate(), bp2);
1492 CHECK_EQ(7, break_point_hit_count);
1494 CHECK_EQ(8, break_point_hit_count);
1496 // Run without breakpoints.
1497 ClearBreakPointFromJS(env->GetIsolate(), bp1);
1499 CHECK_EQ(8, break_point_hit_count);
1501 v8::Debug::SetDebugEventListener(NULL);
1502 CheckDebuggerUnloaded();
1504 // Make sure that the break point numbers are consecutive.
1510 // Test that break points on scripts identified by name can be set using the
1511 // global Debug object.
1512 TEST(ScriptBreakPointByNameThroughJavaScript) {
1513 break_point_hit_count = 0;
1514 DebugLocalContext env;
1515 v8::HandleScope scope(env->GetIsolate());
1518 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1520 v8::Local<v8::String> script = v8::String::NewFromUtf8(
1524 " a = 0; // line 2\n"
1526 " b = 1; // line 4\n"
1534 " b = 2; // line 12\n"
1536 " b = 3; // line 14\n"
1537 " f(); // line 15\n"
1540 // Compile the script and get the two functions.
1541 v8::ScriptOrigin origin =
1542 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
1543 v8::Script::Compile(script, &origin)->Run();
1544 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
1545 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1546 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
1547 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
1549 // Call f and g without break points.
1550 break_point_hit_count = 0;
1551 f->Call(env->Global(), 0, NULL);
1552 CHECK_EQ(0, break_point_hit_count);
1553 g->Call(env->Global(), 0, NULL);
1554 CHECK_EQ(0, break_point_hit_count);
1556 // Call f and g with break point on line 12.
1557 int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 12, 0);
1558 break_point_hit_count = 0;
1559 f->Call(env->Global(), 0, NULL);
1560 CHECK_EQ(0, break_point_hit_count);
1561 g->Call(env->Global(), 0, NULL);
1562 CHECK_EQ(1, break_point_hit_count);
1564 // Remove the break point again.
1565 break_point_hit_count = 0;
1566 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
1567 f->Call(env->Global(), 0, NULL);
1568 CHECK_EQ(0, break_point_hit_count);
1569 g->Call(env->Global(), 0, NULL);
1570 CHECK_EQ(0, break_point_hit_count);
1572 // Call f and g with break point on line 2.
1573 int sbp2 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 2, 0);
1574 break_point_hit_count = 0;
1575 f->Call(env->Global(), 0, NULL);
1576 CHECK_EQ(1, break_point_hit_count);
1577 g->Call(env->Global(), 0, NULL);
1578 CHECK_EQ(2, break_point_hit_count);
1580 // Call f and g with break point on line 2, 4, 12, 14 and 15.
1581 int sbp3 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 4, 0);
1582 int sbp4 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 12, 0);
1583 int sbp5 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 14, 0);
1584 int sbp6 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 15, 0);
1585 break_point_hit_count = 0;
1586 f->Call(env->Global(), 0, NULL);
1587 CHECK_EQ(2, break_point_hit_count);
1588 g->Call(env->Global(), 0, NULL);
1589 CHECK_EQ(7, break_point_hit_count);
1591 // Remove all the break points again.
1592 break_point_hit_count = 0;
1593 ClearBreakPointFromJS(env->GetIsolate(), sbp2);
1594 ClearBreakPointFromJS(env->GetIsolate(), sbp3);
1595 ClearBreakPointFromJS(env->GetIsolate(), sbp4);
1596 ClearBreakPointFromJS(env->GetIsolate(), sbp5);
1597 ClearBreakPointFromJS(env->GetIsolate(), sbp6);
1598 f->Call(env->Global(), 0, NULL);
1599 CHECK_EQ(0, break_point_hit_count);
1600 g->Call(env->Global(), 0, NULL);
1601 CHECK_EQ(0, break_point_hit_count);
1603 v8::Debug::SetDebugEventListener(NULL);
1604 CheckDebuggerUnloaded();
1606 // Make sure that the break point numbers are consecutive.
1616 TEST(ScriptBreakPointByIdThroughJavaScript) {
1617 break_point_hit_count = 0;
1618 DebugLocalContext env;
1619 v8::HandleScope scope(env->GetIsolate());
1622 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1624 v8::Local<v8::String> source = v8::String::NewFromUtf8(
1628 " a = 0; // line 2\n"
1630 " b = 1; // line 4\n"
1638 " b = 2; // line 12\n"
1640 " b = 3; // line 14\n"
1641 " f(); // line 15\n"
1644 // Compile the script and get the two functions.
1645 v8::ScriptOrigin origin =
1646 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
1647 v8::Local<v8::Script> script = v8::Script::Compile(source, &origin);
1649 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
1650 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1651 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
1652 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
1654 // Get the script id knowing that internally it is a 32 integer.
1655 int script_id = script->GetUnboundScript()->GetId();
1657 // Call f and g without break points.
1658 break_point_hit_count = 0;
1659 f->Call(env->Global(), 0, NULL);
1660 CHECK_EQ(0, break_point_hit_count);
1661 g->Call(env->Global(), 0, NULL);
1662 CHECK_EQ(0, break_point_hit_count);
1664 // Call f and g with break point on line 12.
1665 int sbp1 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 12, 0);
1666 break_point_hit_count = 0;
1667 f->Call(env->Global(), 0, NULL);
1668 CHECK_EQ(0, break_point_hit_count);
1669 g->Call(env->Global(), 0, NULL);
1670 CHECK_EQ(1, break_point_hit_count);
1672 // Remove the break point again.
1673 break_point_hit_count = 0;
1674 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
1675 f->Call(env->Global(), 0, NULL);
1676 CHECK_EQ(0, break_point_hit_count);
1677 g->Call(env->Global(), 0, NULL);
1678 CHECK_EQ(0, break_point_hit_count);
1680 // Call f and g with break point on line 2.
1681 int sbp2 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 2, 0);
1682 break_point_hit_count = 0;
1683 f->Call(env->Global(), 0, NULL);
1684 CHECK_EQ(1, break_point_hit_count);
1685 g->Call(env->Global(), 0, NULL);
1686 CHECK_EQ(2, break_point_hit_count);
1688 // Call f and g with break point on line 2, 4, 12, 14 and 15.
1689 int sbp3 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 4, 0);
1690 int sbp4 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 12, 0);
1691 int sbp5 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 14, 0);
1692 int sbp6 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 15, 0);
1693 break_point_hit_count = 0;
1694 f->Call(env->Global(), 0, NULL);
1695 CHECK_EQ(2, break_point_hit_count);
1696 g->Call(env->Global(), 0, NULL);
1697 CHECK_EQ(7, break_point_hit_count);
1699 // Remove all the break points again.
1700 break_point_hit_count = 0;
1701 ClearBreakPointFromJS(env->GetIsolate(), sbp2);
1702 ClearBreakPointFromJS(env->GetIsolate(), sbp3);
1703 ClearBreakPointFromJS(env->GetIsolate(), sbp4);
1704 ClearBreakPointFromJS(env->GetIsolate(), sbp5);
1705 ClearBreakPointFromJS(env->GetIsolate(), sbp6);
1706 f->Call(env->Global(), 0, NULL);
1707 CHECK_EQ(0, break_point_hit_count);
1708 g->Call(env->Global(), 0, NULL);
1709 CHECK_EQ(0, break_point_hit_count);
1711 v8::Debug::SetDebugEventListener(NULL);
1712 CheckDebuggerUnloaded();
1714 // Make sure that the break point numbers are consecutive.
1724 // Test conditional script break points.
1725 TEST(EnableDisableScriptBreakPoint) {
1726 break_point_hit_count = 0;
1727 DebugLocalContext env;
1728 v8::HandleScope scope(env->GetIsolate());
1731 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1733 v8::Local<v8::String> script = v8::String::NewFromUtf8(
1736 " a = 0; // line 1\n"
1739 // Compile the script and get function f.
1740 v8::ScriptOrigin origin =
1741 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
1742 v8::Script::Compile(script, &origin)->Run();
1743 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
1744 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1746 // Set script break point on line 1 (in function f).
1747 int sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0);
1749 // Call f while enabeling and disabling the script break point.
1750 break_point_hit_count = 0;
1751 f->Call(env->Global(), 0, NULL);
1752 CHECK_EQ(1, break_point_hit_count);
1754 DisableScriptBreakPointFromJS(env->GetIsolate(), sbp);
1755 f->Call(env->Global(), 0, NULL);
1756 CHECK_EQ(1, break_point_hit_count);
1758 EnableScriptBreakPointFromJS(env->GetIsolate(), sbp);
1759 f->Call(env->Global(), 0, NULL);
1760 CHECK_EQ(2, break_point_hit_count);
1762 DisableScriptBreakPointFromJS(env->GetIsolate(), sbp);
1763 f->Call(env->Global(), 0, NULL);
1764 CHECK_EQ(2, break_point_hit_count);
1766 // Reload the script and get f again checking that the disabeling survives.
1767 v8::Script::Compile(script, &origin)->Run();
1768 f = v8::Local<v8::Function>::Cast(
1769 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1770 f->Call(env->Global(), 0, NULL);
1771 CHECK_EQ(2, break_point_hit_count);
1773 EnableScriptBreakPointFromJS(env->GetIsolate(), sbp);
1774 f->Call(env->Global(), 0, NULL);
1775 CHECK_EQ(3, break_point_hit_count);
1777 v8::Debug::SetDebugEventListener(NULL);
1778 CheckDebuggerUnloaded();
1782 // Test conditional script break points.
1783 TEST(ConditionalScriptBreakPoint) {
1784 break_point_hit_count = 0;
1785 DebugLocalContext env;
1786 v8::HandleScope scope(env->GetIsolate());
1789 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1791 v8::Local<v8::String> script = v8::String::NewFromUtf8(
1795 " g(count++); // line 2\n"
1798 " var a=x; // line 5\n"
1801 // Compile the script and get function f.
1802 v8::ScriptOrigin origin =
1803 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
1804 v8::Script::Compile(script, &origin)->Run();
1805 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
1806 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1808 // Set script break point on line 5 (in function g).
1809 int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 5, 0);
1811 // Call f with different conditions on the script break point.
1812 break_point_hit_count = 0;
1813 ChangeScriptBreakPointConditionFromJS(env->GetIsolate(), sbp1, "false");
1814 f->Call(env->Global(), 0, NULL);
1815 CHECK_EQ(0, break_point_hit_count);
1817 ChangeScriptBreakPointConditionFromJS(env->GetIsolate(), sbp1, "true");
1818 break_point_hit_count = 0;
1819 f->Call(env->Global(), 0, NULL);
1820 CHECK_EQ(1, break_point_hit_count);
1822 ChangeScriptBreakPointConditionFromJS(env->GetIsolate(), sbp1, "x % 2 == 0");
1823 break_point_hit_count = 0;
1824 for (int i = 0; i < 10; i++) {
1825 f->Call(env->Global(), 0, NULL);
1827 CHECK_EQ(5, break_point_hit_count);
1829 // Reload the script and get f again checking that the condition survives.
1830 v8::Script::Compile(script, &origin)->Run();
1831 f = v8::Local<v8::Function>::Cast(
1832 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1834 break_point_hit_count = 0;
1835 for (int i = 0; i < 10; i++) {
1836 f->Call(env->Global(), 0, NULL);
1838 CHECK_EQ(5, break_point_hit_count);
1840 v8::Debug::SetDebugEventListener(NULL);
1841 CheckDebuggerUnloaded();
1845 // Test ignore count on script break points.
1846 TEST(ScriptBreakPointIgnoreCount) {
1847 break_point_hit_count = 0;
1848 DebugLocalContext env;
1849 v8::HandleScope scope(env->GetIsolate());
1852 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1854 v8::Local<v8::String> script = v8::String::NewFromUtf8(
1857 " a = 0; // line 1\n"
1860 // Compile the script and get function f.
1861 v8::ScriptOrigin origin =
1862 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
1863 v8::Script::Compile(script, &origin)->Run();
1864 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
1865 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1867 // Set script break point on line 1 (in function f).
1868 int sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0);
1870 // Call f with different ignores on the script break point.
1871 break_point_hit_count = 0;
1872 ChangeScriptBreakPointIgnoreCountFromJS(env->GetIsolate(), sbp, 1);
1873 f->Call(env->Global(), 0, NULL);
1874 CHECK_EQ(0, break_point_hit_count);
1875 f->Call(env->Global(), 0, NULL);
1876 CHECK_EQ(1, break_point_hit_count);
1878 ChangeScriptBreakPointIgnoreCountFromJS(env->GetIsolate(), sbp, 5);
1879 break_point_hit_count = 0;
1880 for (int i = 0; i < 10; i++) {
1881 f->Call(env->Global(), 0, NULL);
1883 CHECK_EQ(5, break_point_hit_count);
1885 // Reload the script and get f again checking that the ignore survives.
1886 v8::Script::Compile(script, &origin)->Run();
1887 f = v8::Local<v8::Function>::Cast(
1888 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1890 break_point_hit_count = 0;
1891 for (int i = 0; i < 10; i++) {
1892 f->Call(env->Global(), 0, NULL);
1894 CHECK_EQ(5, break_point_hit_count);
1896 v8::Debug::SetDebugEventListener(NULL);
1897 CheckDebuggerUnloaded();
1901 // Test that script break points survive when a script is reloaded.
1902 TEST(ScriptBreakPointReload) {
1903 break_point_hit_count = 0;
1904 DebugLocalContext env;
1905 v8::HandleScope scope(env->GetIsolate());
1908 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1910 v8::Local<v8::Function> f;
1911 v8::Local<v8::String> script = v8::String::NewFromUtf8(
1915 " a = 0; // line 2\n"
1917 " b = 1; // line 4\n"
1921 v8::ScriptOrigin origin_1 =
1922 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "1"));
1923 v8::ScriptOrigin origin_2 =
1924 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "2"));
1926 // Set a script break point before the script is loaded.
1927 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "1", 2, 0);
1929 // Compile the script and get the function.
1930 v8::Script::Compile(script, &origin_1)->Run();
1931 f = v8::Local<v8::Function>::Cast(
1932 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1934 // Call f and check that the script break point is active.
1935 break_point_hit_count = 0;
1936 f->Call(env->Global(), 0, NULL);
1937 CHECK_EQ(1, break_point_hit_count);
1939 // Compile the script again with a different script data and get the
1941 v8::Script::Compile(script, &origin_2)->Run();
1942 f = v8::Local<v8::Function>::Cast(
1943 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1945 // Call f and check that no break points are set.
1946 break_point_hit_count = 0;
1947 f->Call(env->Global(), 0, NULL);
1948 CHECK_EQ(0, break_point_hit_count);
1950 // Compile the script again and get the function.
1951 v8::Script::Compile(script, &origin_1)->Run();
1952 f = v8::Local<v8::Function>::Cast(
1953 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1955 // Call f and check that the script break point is active.
1956 break_point_hit_count = 0;
1957 f->Call(env->Global(), 0, NULL);
1958 CHECK_EQ(1, break_point_hit_count);
1960 v8::Debug::SetDebugEventListener(NULL);
1961 CheckDebuggerUnloaded();
1965 // Test when several scripts has the same script data
1966 TEST(ScriptBreakPointMultiple) {
1967 break_point_hit_count = 0;
1968 DebugLocalContext env;
1969 v8::HandleScope scope(env->GetIsolate());
1972 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1974 v8::Local<v8::Function> f;
1975 v8::Local<v8::String> script_f =
1976 v8::String::NewFromUtf8(env->GetIsolate(),
1978 " a = 0; // line 1\n"
1981 v8::Local<v8::Function> g;
1982 v8::Local<v8::String> script_g =
1983 v8::String::NewFromUtf8(env->GetIsolate(),
1985 " b = 0; // line 1\n"
1988 v8::ScriptOrigin origin =
1989 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
1991 // Set a script break point before the scripts are loaded.
1992 int sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0);
1994 // Compile the scripts with same script data and get the functions.
1995 v8::Script::Compile(script_f, &origin)->Run();
1996 f = v8::Local<v8::Function>::Cast(
1997 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1998 v8::Script::Compile(script_g, &origin)->Run();
1999 g = v8::Local<v8::Function>::Cast(
2000 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
2002 // Call f and g and check that the script break point is active.
2003 break_point_hit_count = 0;
2004 f->Call(env->Global(), 0, NULL);
2005 CHECK_EQ(1, break_point_hit_count);
2006 g->Call(env->Global(), 0, NULL);
2007 CHECK_EQ(2, break_point_hit_count);
2009 // Clear the script break point.
2010 ClearBreakPointFromJS(env->GetIsolate(), sbp);
2012 // Call f and g and check that the script break point is no longer active.
2013 break_point_hit_count = 0;
2014 f->Call(env->Global(), 0, NULL);
2015 CHECK_EQ(0, break_point_hit_count);
2016 g->Call(env->Global(), 0, NULL);
2017 CHECK_EQ(0, break_point_hit_count);
2019 // Set script break point with the scripts loaded.
2020 sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0);
2022 // Call f and g and check that the script break point is active.
2023 break_point_hit_count = 0;
2024 f->Call(env->Global(), 0, NULL);
2025 CHECK_EQ(1, break_point_hit_count);
2026 g->Call(env->Global(), 0, NULL);
2027 CHECK_EQ(2, break_point_hit_count);
2029 v8::Debug::SetDebugEventListener(NULL);
2030 CheckDebuggerUnloaded();
2034 // Test the script origin which has both name and line offset.
2035 TEST(ScriptBreakPointLineOffset) {
2036 break_point_hit_count = 0;
2037 DebugLocalContext env;
2038 v8::HandleScope scope(env->GetIsolate());
2041 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2043 v8::Local<v8::Function> f;
2044 v8::Local<v8::String> script = v8::String::NewFromUtf8(
2047 " a = 0; // line 8 as this script has line offset 7\n"
2048 " b = 0; // line 9 as this script has line offset 7\n"
2051 // Create script origin both name and line offset.
2052 v8::ScriptOrigin origin(
2053 v8::String::NewFromUtf8(env->GetIsolate(), "test.html"),
2054 v8::Integer::New(env->GetIsolate(), 7));
2056 // Set two script break points before the script is loaded.
2058 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 8, 0);
2060 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 9, 0);
2062 // Compile the script and get the function.
2063 v8::Script::Compile(script, &origin)->Run();
2064 f = v8::Local<v8::Function>::Cast(
2065 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
2067 // Call f and check that the script break point is active.
2068 break_point_hit_count = 0;
2069 f->Call(env->Global(), 0, NULL);
2070 CHECK_EQ(2, break_point_hit_count);
2072 // Clear the script break points.
2073 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
2074 ClearBreakPointFromJS(env->GetIsolate(), sbp2);
2076 // Call f and check that no script break points are active.
2077 break_point_hit_count = 0;
2078 f->Call(env->Global(), 0, NULL);
2079 CHECK_EQ(0, break_point_hit_count);
2081 // Set a script break point with the script loaded.
2082 sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 9, 0);
2084 // Call f and check that the script break point is active.
2085 break_point_hit_count = 0;
2086 f->Call(env->Global(), 0, NULL);
2087 CHECK_EQ(1, break_point_hit_count);
2089 v8::Debug::SetDebugEventListener(NULL);
2090 CheckDebuggerUnloaded();
2094 // Test script break points set on lines.
2095 TEST(ScriptBreakPointLine) {
2096 DebugLocalContext env;
2097 v8::HandleScope scope(env->GetIsolate());
2100 // Create a function for checking the function when hitting a break point.
2101 frame_function_name = CompileFunction(&env,
2102 frame_function_name_source,
2103 "frame_function_name");
2105 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2107 v8::Local<v8::Function> f;
2108 v8::Local<v8::Function> g;
2109 v8::Local<v8::String> script =
2110 v8::String::NewFromUtf8(env->GetIsolate(),
2113 " a = 1; // line 2\n"
2115 " a = 2; // line 4\n"
2116 " /* xx */ function g() { // line 5\n"
2117 " function h() { // line 6\n"
2118 " a = 3; // line 7\n"
2121 " a = 4; // line 10\n"
2123 " a=5; // line 12");
2125 // Set a couple script break point before the script is loaded.
2127 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 0, -1);
2129 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 1, -1);
2131 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 5, -1);
2133 // Compile the script and get the function.
2134 break_point_hit_count = 0;
2135 v8::ScriptOrigin origin(
2136 v8::String::NewFromUtf8(env->GetIsolate(), "test.html"),
2137 v8::Integer::New(env->GetIsolate(), 0));
2138 v8::Script::Compile(script, &origin)->Run();
2139 f = v8::Local<v8::Function>::Cast(
2140 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
2141 g = v8::Local<v8::Function>::Cast(
2142 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
2144 // Check that a break point was hit when the script was run.
2145 CHECK_EQ(1, break_point_hit_count);
2146 CHECK_EQ(0, StrLength(last_function_hit));
2148 // Call f and check that the script break point.
2149 f->Call(env->Global(), 0, NULL);
2150 CHECK_EQ(2, break_point_hit_count);
2151 CHECK_EQ("f", last_function_hit);
2153 // Call g and check that the script break point.
2154 g->Call(env->Global(), 0, NULL);
2155 CHECK_EQ(3, break_point_hit_count);
2156 CHECK_EQ("g", last_function_hit);
2158 // Clear the script break point on g and set one on h.
2159 ClearBreakPointFromJS(env->GetIsolate(), sbp3);
2161 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 6, -1);
2163 // Call g and check that the script break point in h is hit.
2164 g->Call(env->Global(), 0, NULL);
2165 CHECK_EQ(4, break_point_hit_count);
2166 CHECK_EQ("h", last_function_hit);
2168 // Clear break points in f and h. Set a new one in the script between
2169 // functions f and g and test that there is no break points in f and g any
2171 ClearBreakPointFromJS(env->GetIsolate(), sbp2);
2172 ClearBreakPointFromJS(env->GetIsolate(), sbp4);
2174 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 4, -1);
2175 break_point_hit_count = 0;
2176 f->Call(env->Global(), 0, NULL);
2177 g->Call(env->Global(), 0, NULL);
2178 CHECK_EQ(0, break_point_hit_count);
2180 // Reload the script which should hit two break points.
2181 break_point_hit_count = 0;
2182 v8::Script::Compile(script, &origin)->Run();
2183 CHECK_EQ(2, break_point_hit_count);
2184 CHECK_EQ(0, StrLength(last_function_hit));
2186 // Set a break point in the code after the last function decleration.
2188 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 12, -1);
2190 // Reload the script which should hit three break points.
2191 break_point_hit_count = 0;
2192 v8::Script::Compile(script, &origin)->Run();
2193 CHECK_EQ(3, break_point_hit_count);
2194 CHECK_EQ(0, StrLength(last_function_hit));
2196 // Clear the last break points, and reload the script which should not hit any
2198 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
2199 ClearBreakPointFromJS(env->GetIsolate(), sbp5);
2200 ClearBreakPointFromJS(env->GetIsolate(), sbp6);
2201 break_point_hit_count = 0;
2202 v8::Script::Compile(script, &origin)->Run();
2203 CHECK_EQ(0, break_point_hit_count);
2205 v8::Debug::SetDebugEventListener(NULL);
2206 CheckDebuggerUnloaded();
2210 // Test top level script break points set on lines.
2211 TEST(ScriptBreakPointLineTopLevel) {
2212 DebugLocalContext env;
2213 v8::HandleScope scope(env->GetIsolate());
2216 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2218 v8::Local<v8::String> script =
2219 v8::String::NewFromUtf8(env->GetIsolate(),
2221 " a = 1; // line 1\n"
2223 "a = 2; // line 3\n");
2224 v8::Local<v8::Function> f;
2226 v8::HandleScope scope(env->GetIsolate());
2227 CompileRunWithOrigin(script, "test.html");
2229 f = v8::Local<v8::Function>::Cast(
2230 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
2232 CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
2234 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 3, -1);
2236 // Call f and check that there was no break points.
2237 break_point_hit_count = 0;
2238 f->Call(env->Global(), 0, NULL);
2239 CHECK_EQ(0, break_point_hit_count);
2241 // Recompile and run script and check that break point was hit.
2242 break_point_hit_count = 0;
2243 CompileRunWithOrigin(script, "test.html");
2244 CHECK_EQ(1, break_point_hit_count);
2246 // Call f and check that there are still no break points.
2247 break_point_hit_count = 0;
2248 f = v8::Local<v8::Function>::Cast(
2249 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
2250 CHECK_EQ(0, break_point_hit_count);
2252 v8::Debug::SetDebugEventListener(NULL);
2253 CheckDebuggerUnloaded();
2257 // Test that it is possible to add and remove break points in a top level
2258 // function which has no references but has not been collected yet.
2259 TEST(ScriptBreakPointTopLevelCrash) {
2260 DebugLocalContext env;
2261 v8::HandleScope scope(env->GetIsolate());
2264 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2266 v8::Local<v8::String> script_source =
2267 v8::String::NewFromUtf8(env->GetIsolate(),
2274 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 3, -1);
2276 v8::HandleScope scope(env->GetIsolate());
2277 break_point_hit_count = 0;
2278 CompileRunWithOrigin(script_source, "test.html");
2279 CHECK_EQ(1, break_point_hit_count);
2283 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 3, -1);
2284 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
2285 ClearBreakPointFromJS(env->GetIsolate(), sbp2);
2287 v8::Debug::SetDebugEventListener(NULL);
2288 CheckDebuggerUnloaded();
2292 // Test that it is possible to remove the last break point for a function
2293 // inside the break handling of that break point.
2294 TEST(RemoveBreakPointInBreak) {
2295 DebugLocalContext env;
2296 v8::HandleScope scope(env->GetIsolate());
2298 v8::Local<v8::Function> foo =
2299 CompileFunction(&env, "function foo(){a=1;}", "foo");
2300 debug_event_remove_break_point = SetBreakPoint(foo, 0);
2302 // Register the debug event listener pasing the function
2303 v8::Debug::SetDebugEventListener(DebugEventRemoveBreakPoint, foo);
2305 break_point_hit_count = 0;
2306 foo->Call(env->Global(), 0, NULL);
2307 CHECK_EQ(1, break_point_hit_count);
2309 break_point_hit_count = 0;
2310 foo->Call(env->Global(), 0, NULL);
2311 CHECK_EQ(0, break_point_hit_count);
2313 v8::Debug::SetDebugEventListener(NULL);
2314 CheckDebuggerUnloaded();
2318 // Test that the debugger statement causes a break.
2319 TEST(DebuggerStatement) {
2320 break_point_hit_count = 0;
2321 DebugLocalContext env;
2322 v8::HandleScope scope(env->GetIsolate());
2323 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2324 v8::Script::Compile(
2325 v8::String::NewFromUtf8(env->GetIsolate(), "function bar(){debugger}"))
2327 v8::Script::Compile(
2328 v8::String::NewFromUtf8(env->GetIsolate(),
2329 "function foo(){debugger;debugger;}"))->Run();
2330 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
2331 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo")));
2332 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
2333 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "bar")));
2335 // Run function with debugger statement
2336 bar->Call(env->Global(), 0, NULL);
2337 CHECK_EQ(1, break_point_hit_count);
2339 // Run function with two debugger statement
2340 foo->Call(env->Global(), 0, NULL);
2341 CHECK_EQ(3, break_point_hit_count);
2343 v8::Debug::SetDebugEventListener(NULL);
2344 CheckDebuggerUnloaded();
2348 // Test setting a breakpoint on the debugger statement.
2349 TEST(DebuggerStatementBreakpoint) {
2350 break_point_hit_count = 0;
2351 DebugLocalContext env;
2352 v8::HandleScope scope(env->GetIsolate());
2353 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2354 v8::Script::Compile(
2355 v8::String::NewFromUtf8(env->GetIsolate(), "function foo(){debugger;}"))
2357 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
2358 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo")));
2360 // The debugger statement triggers breakpint hit
2361 foo->Call(env->Global(), 0, NULL);
2362 CHECK_EQ(1, break_point_hit_count);
2364 int bp = SetBreakPoint(foo, 0);
2366 // Set breakpoint does not duplicate hits
2367 foo->Call(env->Global(), 0, NULL);
2368 CHECK_EQ(2, break_point_hit_count);
2370 ClearBreakPoint(bp);
2371 v8::Debug::SetDebugEventListener(NULL);
2372 CheckDebuggerUnloaded();
2376 // Test that the evaluation of expressions when a break point is hit generates
2377 // the correct results.
2378 TEST(DebugEvaluate) {
2379 DebugLocalContext env;
2380 v8::Isolate* isolate = env->GetIsolate();
2381 v8::HandleScope scope(isolate);
2384 // Create a function for checking the evaluation when hitting a break point.
2385 evaluate_check_function = CompileFunction(&env,
2386 evaluate_check_source,
2388 // Register the debug event listener
2389 v8::Debug::SetDebugEventListener(DebugEventEvaluate);
2391 // Different expected vaules of x and a when in a break point (u = undefined,
2392 // d = Hello, world!).
2393 struct EvaluateCheck checks_uu[] = {
2394 {"x", v8::Undefined(isolate)},
2395 {"a", v8::Undefined(isolate)},
2396 {NULL, v8::Handle<v8::Value>()}
2398 struct EvaluateCheck checks_hu[] = {
2399 {"x", v8::String::NewFromUtf8(env->GetIsolate(), "Hello, world!")},
2400 {"a", v8::Undefined(isolate)},
2401 {NULL, v8::Handle<v8::Value>()}
2403 struct EvaluateCheck checks_hh[] = {
2404 {"x", v8::String::NewFromUtf8(env->GetIsolate(), "Hello, world!")},
2405 {"a", v8::String::NewFromUtf8(env->GetIsolate(), "Hello, world!")},
2406 {NULL, v8::Handle<v8::Value>()}
2409 // Simple test function. The "y=0" is in the function foo to provide a break
2410 // location. For "y=0" the "y" is at position 15 in the foo function
2411 // therefore setting breakpoint at position 15 will break at "y=0" and
2412 // setting it higher will break after.
2413 v8::Local<v8::Function> foo = CompileFunction(&env,
2416 " y=0;" // To ensure break location 1.
2418 " y=0;" // To ensure break location 2.
2421 const int foo_break_position_1 = 15;
2422 const int foo_break_position_2 = 29;
2424 // Arguments with one parameter "Hello, world!"
2425 v8::Handle<v8::Value> argv_foo[1] = {
2426 v8::String::NewFromUtf8(env->GetIsolate(), "Hello, world!")};
2428 // Call foo with breakpoint set before a=x and undefined as parameter.
2429 int bp = SetBreakPoint(foo, foo_break_position_1);
2431 foo->Call(env->Global(), 0, NULL);
2433 // Call foo with breakpoint set before a=x and parameter "Hello, world!".
2435 foo->Call(env->Global(), 1, argv_foo);
2437 // Call foo with breakpoint set after a=x and parameter "Hello, world!".
2438 ClearBreakPoint(bp);
2439 SetBreakPoint(foo, foo_break_position_2);
2441 foo->Call(env->Global(), 1, argv_foo);
2443 // Test that overriding Object.prototype will not interfere into evaluation
2445 v8::Local<v8::Function> zoo =
2446 CompileFunction(&env,
2450 " Object.prototype.x = 42;"
2452 " y=0;" // To ensure break location.
2453 " delete Object.prototype.x;"
2457 const int zoo_break_position = 50;
2459 // Arguments with one parameter "Hello, world!"
2460 v8::Handle<v8::Value> argv_zoo[1] = {
2461 v8::String::NewFromUtf8(env->GetIsolate(), "Hello, world!")};
2463 // Call zoo with breakpoint set at y=0.
2464 DebugEventCounterClear();
2465 bp = SetBreakPoint(zoo, zoo_break_position);
2467 zoo->Call(env->Global(), 1, argv_zoo);
2468 CHECK_EQ(1, break_point_hit_count);
2469 ClearBreakPoint(bp);
2471 // Test function with an inner function. The "y=0" is in function barbar
2472 // to provide a break location. For "y=0" the "y" is at position 8 in the
2473 // barbar function therefore setting breakpoint at position 8 will break at
2474 // "y=0" and setting it higher will break after.
2475 v8::Local<v8::Function> bar = CompileFunction(&env,
2477 "x = 'Goodbye, world!';"
2478 "function bar(x, b) {"
2480 " function barbar() {"
2481 " y=0; /* To ensure break location.*/"
2484 " debug.Debug.clearAllBreakPoints();"
2489 const int barbar_break_position = 8;
2491 // Call bar setting breakpoint before a=x in barbar and undefined as
2494 v8::Handle<v8::Value> argv_bar_1[2] = {
2495 v8::Undefined(isolate),
2496 v8::Number::New(isolate, barbar_break_position)
2498 bar->Call(env->Global(), 2, argv_bar_1);
2500 // Call bar setting breakpoint before a=x in barbar and parameter
2503 v8::Handle<v8::Value> argv_bar_2[2] = {
2504 v8::String::NewFromUtf8(env->GetIsolate(), "Hello, world!"),
2505 v8::Number::New(env->GetIsolate(), barbar_break_position)
2507 bar->Call(env->Global(), 2, argv_bar_2);
2509 // Call bar setting breakpoint after a=x in barbar and parameter
2512 v8::Handle<v8::Value> argv_bar_3[2] = {
2513 v8::String::NewFromUtf8(env->GetIsolate(), "Hello, world!"),
2514 v8::Number::New(env->GetIsolate(), barbar_break_position + 1)
2516 bar->Call(env->Global(), 2, argv_bar_3);
2518 v8::Debug::SetDebugEventListener(NULL);
2519 CheckDebuggerUnloaded();
2523 int debugEventCount = 0;
2524 static void CheckDebugEvent(const v8::Debug::EventDetails& eventDetails) {
2525 if (eventDetails.GetEvent() == v8::Break) ++debugEventCount;
2529 // Test that the conditional breakpoints work event if code generation from
2530 // strings is prohibited in the debugee context.
2531 TEST(ConditionalBreakpointWithCodeGenerationDisallowed) {
2532 DebugLocalContext env;
2533 v8::HandleScope scope(env->GetIsolate());
2536 v8::Debug::SetDebugEventListener(CheckDebugEvent);
2538 v8::Local<v8::Function> foo = CompileFunction(&env,
2539 "function foo(x) {\n"
2540 " var s = 'String value2';\n"
2545 // Set conditional breakpoint with condition 'true'.
2546 CompileRun("debug.Debug.setBreakPoint(foo, 2, 0, 'true')");
2548 debugEventCount = 0;
2549 env->AllowCodeGenerationFromStrings(false);
2550 foo->Call(env->Global(), 0, NULL);
2551 CHECK_EQ(1, debugEventCount);
2553 v8::Debug::SetDebugEventListener(NULL);
2554 CheckDebuggerUnloaded();
2558 bool checkedDebugEvals = true;
2559 v8::Handle<v8::Function> checkGlobalEvalFunction;
2560 v8::Handle<v8::Function> checkFrameEvalFunction;
2561 static void CheckDebugEval(const v8::Debug::EventDetails& eventDetails) {
2562 if (eventDetails.GetEvent() == v8::Break) {
2564 v8::HandleScope handleScope(CcTest::isolate());
2566 v8::Handle<v8::Value> args[] = { eventDetails.GetExecutionState() };
2567 CHECK(checkGlobalEvalFunction->Call(
2568 eventDetails.GetEventContext()->Global(), 1, args)->IsTrue());
2569 CHECK(checkFrameEvalFunction->Call(
2570 eventDetails.GetEventContext()->Global(), 1, args)->IsTrue());
2575 // Test that the evaluation of expressions when a break point is hit generates
2576 // the correct results in case code generation from strings is disallowed in the
2578 TEST(DebugEvaluateWithCodeGenerationDisallowed) {
2579 DebugLocalContext env;
2580 v8::HandleScope scope(env->GetIsolate());
2583 v8::Debug::SetDebugEventListener(CheckDebugEval);
2585 v8::Local<v8::Function> foo = CompileFunction(&env,
2586 "var global = 'Global';\n"
2587 "function foo(x) {\n"
2588 " var local = 'Local';\n"
2590 " return local + x;\n"
2593 checkGlobalEvalFunction = CompileFunction(&env,
2594 "function checkGlobalEval(exec_state) {\n"
2595 " return exec_state.evaluateGlobal('global').value() === 'Global';\n"
2599 checkFrameEvalFunction = CompileFunction(&env,
2600 "function checkFrameEval(exec_state) {\n"
2601 " return exec_state.frame(0).evaluate('local').value() === 'Local';\n"
2604 debugEventCount = 0;
2605 env->AllowCodeGenerationFromStrings(false);
2606 foo->Call(env->Global(), 0, NULL);
2607 CHECK_EQ(1, debugEventCount);
2609 checkGlobalEvalFunction.Clear();
2610 checkFrameEvalFunction.Clear();
2611 v8::Debug::SetDebugEventListener(NULL);
2612 CheckDebuggerUnloaded();
2616 // Copies a C string to a 16-bit string. Does not check for buffer overflow.
2617 // Does not use the V8 engine to convert strings, so it can be used
2618 // in any thread. Returns the length of the string.
2619 int AsciiToUtf16(const char* input_buffer, uint16_t* output_buffer) {
2621 for (i = 0; input_buffer[i] != '\0'; ++i) {
2622 // ASCII does not use chars > 127, but be careful anyway.
2623 output_buffer[i] = static_cast<unsigned char>(input_buffer[i]);
2625 output_buffer[i] = 0;
2630 // Copies a 16-bit string to a C string by dropping the high byte of
2631 // each character. Does not check for buffer overflow.
2632 // Can be used in any thread. Requires string length as an input.
2633 int Utf16ToAscii(const uint16_t* input_buffer, int length,
2634 char* output_buffer, int output_len = -1) {
2635 if (output_len >= 0) {
2636 if (length > output_len - 1) {
2637 length = output_len - 1;
2641 for (int i = 0; i < length; ++i) {
2642 output_buffer[i] = static_cast<char>(input_buffer[i]);
2644 output_buffer[length] = '\0';
2649 // We match parts of the message to get evaluate result int value.
2650 bool GetEvaluateStringResult(char *message, char* buffer, int buffer_size) {
2651 if (strstr(message, "\"command\":\"evaluate\"") == NULL) {
2654 const char* prefix = "\"text\":\"";
2655 char* pos1 = strstr(message, prefix);
2659 pos1 += strlen(prefix);
2660 char* pos2 = strchr(pos1, '"');
2664 Vector<char> buf(buffer, buffer_size);
2665 int len = static_cast<int>(pos2 - pos1);
2666 if (len > buffer_size - 1) {
2667 len = buffer_size - 1;
2669 StrNCpy(buf, pos1, len);
2670 buffer[buffer_size - 1] = '\0';
2675 struct EvaluateResult {
2676 static const int kBufferSize = 20;
2677 char buffer[kBufferSize];
2680 struct DebugProcessDebugMessagesData {
2681 static const int kArraySize = 5;
2683 EvaluateResult results[kArraySize];
2688 EvaluateResult* current() {
2689 return &results[counter % kArraySize];
2696 DebugProcessDebugMessagesData process_debug_messages_data;
2698 static void DebugProcessDebugMessagesHandler(
2699 const v8::Debug::Message& message) {
2700 v8::Handle<v8::String> json = message.GetJSON();
2701 v8::String::Utf8Value utf8(json);
2702 EvaluateResult* array_item = process_debug_messages_data.current();
2704 bool res = GetEvaluateStringResult(*utf8,
2706 EvaluateResult::kBufferSize);
2708 process_debug_messages_data.next();
2713 // Test that the evaluation of expressions works even from ProcessDebugMessages
2714 // i.e. with empty stack.
2715 TEST(DebugEvaluateWithoutStack) {
2716 v8::Debug::SetMessageHandler(DebugProcessDebugMessagesHandler);
2718 DebugLocalContext env;
2719 v8::HandleScope scope(env->GetIsolate());
2721 const char* source =
2722 "var v1 = 'Pinguin';\n function getAnimal() { return 'Capy' + 'bara'; }";
2724 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), source))
2727 v8::Debug::ProcessDebugMessages();
2729 const int kBufferSize = 1000;
2730 uint16_t buffer[kBufferSize];
2732 const char* command_111 = "{\"seq\":111,"
2733 "\"type\":\"request\","
2734 "\"command\":\"evaluate\","
2737 " \"expression\":\"v1\",\"disable_break\":true"
2740 v8::Isolate* isolate = CcTest::isolate();
2741 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_111, buffer));
2743 const char* command_112 = "{\"seq\":112,"
2744 "\"type\":\"request\","
2745 "\"command\":\"evaluate\","
2748 " \"expression\":\"getAnimal()\",\"disable_break\":true"
2751 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_112, buffer));
2753 const char* command_113 = "{\"seq\":113,"
2754 "\"type\":\"request\","
2755 "\"command\":\"evaluate\","
2758 " \"expression\":\"239 + 566\",\"disable_break\":true"
2761 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_113, buffer));
2763 v8::Debug::ProcessDebugMessages();
2765 CHECK_EQ(3, process_debug_messages_data.counter);
2767 CHECK_EQ(strcmp("Pinguin", process_debug_messages_data.results[0].buffer), 0);
2768 CHECK_EQ(strcmp("Capybara", process_debug_messages_data.results[1].buffer),
2770 CHECK_EQ(strcmp("805", process_debug_messages_data.results[2].buffer), 0);
2772 v8::Debug::SetMessageHandler(NULL);
2773 v8::Debug::SetDebugEventListener(NULL);
2774 CheckDebuggerUnloaded();
2778 // Simple test of the stepping mechanism using only store ICs.
2779 TEST(DebugStepLinear) {
2780 DebugLocalContext env;
2781 v8::HandleScope scope(env->GetIsolate());
2783 // Create a function for testing stepping.
2784 v8::Local<v8::Function> foo = CompileFunction(&env,
2785 "function foo(){a=1;b=1;c=1;}",
2788 // Run foo to allow it to get optimized.
2789 CompileRun("a=0; b=0; c=0; foo();");
2791 SetBreakPoint(foo, 3);
2793 // Register a debug event listener which steps and counts.
2794 v8::Debug::SetDebugEventListener(DebugEventStep);
2796 step_action = StepIn;
2797 break_point_hit_count = 0;
2798 foo->Call(env->Global(), 0, NULL);
2800 // With stepping all break locations are hit.
2801 CHECK_EQ(4, break_point_hit_count);
2803 v8::Debug::SetDebugEventListener(NULL);
2804 CheckDebuggerUnloaded();
2806 // Register a debug event listener which just counts.
2807 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2809 SetBreakPoint(foo, 3);
2810 break_point_hit_count = 0;
2811 foo->Call(env->Global(), 0, NULL);
2813 // Without stepping only active break points are hit.
2814 CHECK_EQ(1, break_point_hit_count);
2816 v8::Debug::SetDebugEventListener(NULL);
2817 CheckDebuggerUnloaded();
2821 // Test of the stepping mechanism for keyed load in a loop.
2822 TEST(DebugStepKeyedLoadLoop) {
2823 DebugLocalContext env;
2824 v8::HandleScope scope(env->GetIsolate());
2826 // Register a debug event listener which steps and counts.
2827 v8::Debug::SetDebugEventListener(DebugEventStep);
2829 // Create a function for testing stepping of keyed load. The statement 'y=1'
2830 // is there to have more than one breakable statement in the loop, TODO(315).
2831 v8::Local<v8::Function> foo = CompileFunction(
2833 "function foo(a) {\n"
2835 " var len = a.length;\n"
2836 " for (var i = 0; i < len; i++) {\n"
2844 // Create array [0,1,2,3,4,5,6,7,8,9]
2845 v8::Local<v8::Array> a = v8::Array::New(env->GetIsolate(), 10);
2846 for (int i = 0; i < 10; i++) {
2847 a->Set(v8::Number::New(env->GetIsolate(), i),
2848 v8::Number::New(env->GetIsolate(), i));
2851 // Call function without any break points to ensure inlining is in place.
2852 const int kArgc = 1;
2853 v8::Handle<v8::Value> args[kArgc] = { a };
2854 foo->Call(env->Global(), kArgc, args);
2856 // Set up break point and step through the function.
2857 SetBreakPoint(foo, 3);
2858 step_action = StepNext;
2859 break_point_hit_count = 0;
2860 foo->Call(env->Global(), kArgc, args);
2862 // With stepping all break locations are hit.
2863 CHECK_EQ(35, break_point_hit_count);
2865 v8::Debug::SetDebugEventListener(NULL);
2866 CheckDebuggerUnloaded();
2870 // Test of the stepping mechanism for keyed store in a loop.
2871 TEST(DebugStepKeyedStoreLoop) {
2872 DebugLocalContext env;
2873 v8::HandleScope scope(env->GetIsolate());
2875 // Register a debug event listener which steps and counts.
2876 v8::Debug::SetDebugEventListener(DebugEventStep);
2878 // Create a function for testing stepping of keyed store. The statement 'y=1'
2879 // is there to have more than one breakable statement in the loop, TODO(315).
2880 v8::Local<v8::Function> foo = CompileFunction(
2882 "function foo(a) {\n"
2883 " var len = a.length;\n"
2884 " for (var i = 0; i < len; i++) {\n"
2892 // Create array [0,1,2,3,4,5,6,7,8,9]
2893 v8::Local<v8::Array> a = v8::Array::New(env->GetIsolate(), 10);
2894 for (int i = 0; i < 10; i++) {
2895 a->Set(v8::Number::New(env->GetIsolate(), i),
2896 v8::Number::New(env->GetIsolate(), i));
2899 // Call function without any break points to ensure inlining is in place.
2900 const int kArgc = 1;
2901 v8::Handle<v8::Value> args[kArgc] = { a };
2902 foo->Call(env->Global(), kArgc, args);
2904 // Set up break point and step through the function.
2905 SetBreakPoint(foo, 3);
2906 step_action = StepNext;
2907 break_point_hit_count = 0;
2908 foo->Call(env->Global(), kArgc, args);
2910 // With stepping all break locations are hit.
2911 CHECK_EQ(34, break_point_hit_count);
2913 v8::Debug::SetDebugEventListener(NULL);
2914 CheckDebuggerUnloaded();
2918 // Test of the stepping mechanism for named load in a loop.
2919 TEST(DebugStepNamedLoadLoop) {
2920 DebugLocalContext env;
2921 v8::HandleScope scope(env->GetIsolate());
2923 // Register a debug event listener which steps and counts.
2924 v8::Debug::SetDebugEventListener(DebugEventStep);
2926 // Create a function for testing stepping of named load.
2927 v8::Local<v8::Function> foo = CompileFunction(
2929 "function foo() {\n"
2932 " for (var i = 0; i < 10; i++) {\n"
2933 " var v = new V(i, i + 1);\n"
2935 " a.length;\n" // Special case: array length.
2936 " s.length;\n" // Special case: string length.
2939 "function V(x, y) {\n"
2945 // Call function without any break points to ensure inlining is in place.
2946 foo->Call(env->Global(), 0, NULL);
2948 // Set up break point and step through the function.
2949 SetBreakPoint(foo, 4);
2950 step_action = StepNext;
2951 break_point_hit_count = 0;
2952 foo->Call(env->Global(), 0, NULL);
2954 // With stepping all break locations are hit.
2955 CHECK_EQ(55, break_point_hit_count);
2957 v8::Debug::SetDebugEventListener(NULL);
2958 CheckDebuggerUnloaded();
2962 static void DoDebugStepNamedStoreLoop(int expected) {
2963 DebugLocalContext env;
2964 v8::HandleScope scope(env->GetIsolate());
2966 // Register a debug event listener which steps and counts.
2967 v8::Debug::SetDebugEventListener(DebugEventStep);
2969 // Create a function for testing stepping of named store.
2970 v8::Local<v8::Function> foo = CompileFunction(
2972 "function foo() {\n"
2974 " for (var i = 0; i < 10; i++) {\n"
2980 // Call function without any break points to ensure inlining is in place.
2981 foo->Call(env->Global(), 0, NULL);
2983 // Set up break point and step through the function.
2984 SetBreakPoint(foo, 3);
2985 step_action = StepNext;
2986 break_point_hit_count = 0;
2987 foo->Call(env->Global(), 0, NULL);
2989 // With stepping all expected break locations are hit.
2990 CHECK_EQ(expected, break_point_hit_count);
2992 v8::Debug::SetDebugEventListener(NULL);
2993 CheckDebuggerUnloaded();
2997 // Test of the stepping mechanism for named load in a loop.
2998 TEST(DebugStepNamedStoreLoop) {
2999 DoDebugStepNamedStoreLoop(24);
3003 // Test the stepping mechanism with different ICs.
3004 TEST(DebugStepLinearMixedICs) {
3005 DebugLocalContext env;
3006 v8::HandleScope scope(env->GetIsolate());
3008 // Register a debug event listener which steps and counts.
3009 v8::Debug::SetDebugEventListener(DebugEventStep);
3011 // Create a function for testing stepping.
3012 v8::Local<v8::Function> foo = CompileFunction(&env,
3013 "function bar() {};"
3016 " var index='name';"
3018 " a=1;b=2;x=a;y[index]=3;x=y[index];bar();}", "foo");
3020 // Run functions to allow them to get optimized.
3021 CompileRun("a=0; b=0; bar(); foo();");
3023 SetBreakPoint(foo, 0);
3025 step_action = StepIn;
3026 break_point_hit_count = 0;
3027 foo->Call(env->Global(), 0, NULL);
3029 // With stepping all break locations are hit.
3030 CHECK_EQ(11, break_point_hit_count);
3032 v8::Debug::SetDebugEventListener(NULL);
3033 CheckDebuggerUnloaded();
3035 // Register a debug event listener which just counts.
3036 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3038 SetBreakPoint(foo, 0);
3039 break_point_hit_count = 0;
3040 foo->Call(env->Global(), 0, NULL);
3042 // Without stepping only active break points are hit.
3043 CHECK_EQ(1, break_point_hit_count);
3045 v8::Debug::SetDebugEventListener(NULL);
3046 CheckDebuggerUnloaded();
3050 TEST(DebugStepDeclarations) {
3051 DebugLocalContext env;
3052 v8::HandleScope scope(env->GetIsolate());
3054 // Register a debug event listener which steps and counts.
3055 v8::Debug::SetDebugEventListener(DebugEventStep);
3057 // Create a function for testing stepping. Run it to allow it to get
3059 const char* src = "function foo() { "
3063 " var d = Math.floor;"
3064 " var e = b + d(1.2);"
3067 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3069 SetBreakPoint(foo, 0);
3071 // Stepping through the declarations.
3072 step_action = StepIn;
3073 break_point_hit_count = 0;
3074 foo->Call(env->Global(), 0, NULL);
3075 CHECK_EQ(6, break_point_hit_count);
3077 // Get rid of the debug event listener.
3078 v8::Debug::SetDebugEventListener(NULL);
3079 CheckDebuggerUnloaded();
3083 TEST(DebugStepLocals) {
3084 DebugLocalContext env;
3085 v8::HandleScope scope(env->GetIsolate());
3087 // Register a debug event listener which steps and counts.
3088 v8::Debug::SetDebugEventListener(DebugEventStep);
3090 // Create a function for testing stepping. Run it to allow it to get
3092 const char* src = "function foo() { "
3097 " a = Math.floor(b);"
3100 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3102 SetBreakPoint(foo, 0);
3104 // Stepping through the declarations.
3105 step_action = StepIn;
3106 break_point_hit_count = 0;
3107 foo->Call(env->Global(), 0, NULL);
3108 CHECK_EQ(6, break_point_hit_count);
3110 // Get rid of the debug event listener.
3111 v8::Debug::SetDebugEventListener(NULL);
3112 CheckDebuggerUnloaded();
3117 DebugLocalContext env;
3118 v8::Isolate* isolate = env->GetIsolate();
3119 v8::HandleScope scope(isolate);
3121 // Register a debug event listener which steps and counts.
3122 v8::Debug::SetDebugEventListener(DebugEventStep);
3124 // Create a function for testing stepping. Run it to allow it to get
3127 const char* src = "function foo(x) { "
3136 "a=0; b=0; c=0; d=0; foo()";
3137 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3138 SetBreakPoint(foo, 0);
3140 // Stepping through the true part.
3141 step_action = StepIn;
3142 break_point_hit_count = 0;
3143 v8::Handle<v8::Value> argv_true[argc] = { v8::True(isolate) };
3144 foo->Call(env->Global(), argc, argv_true);
3145 CHECK_EQ(4, break_point_hit_count);
3147 // Stepping through the false part.
3148 step_action = StepIn;
3149 break_point_hit_count = 0;
3150 v8::Handle<v8::Value> argv_false[argc] = { v8::False(isolate) };
3151 foo->Call(env->Global(), argc, argv_false);
3152 CHECK_EQ(5, break_point_hit_count);
3154 // Get rid of the debug event listener.
3155 v8::Debug::SetDebugEventListener(NULL);
3156 CheckDebuggerUnloaded();
3160 TEST(DebugStepSwitch) {
3161 DebugLocalContext env;
3162 v8::Isolate* isolate = env->GetIsolate();
3163 v8::HandleScope scope(isolate);
3165 // Register a debug event listener which steps and counts.
3166 v8::Debug::SetDebugEventListener(DebugEventStep);
3168 // Create a function for testing stepping. Run it to allow it to get
3171 const char* src = "function foo(x) { "
3186 "a=0; b=0; c=0; d=0; e=0; f=0; foo()";
3187 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3188 SetBreakPoint(foo, 0);
3190 // One case with fall-through.
3191 step_action = StepIn;
3192 break_point_hit_count = 0;
3193 v8::Handle<v8::Value> argv_1[argc] = { v8::Number::New(isolate, 1) };
3194 foo->Call(env->Global(), argc, argv_1);
3195 CHECK_EQ(6, break_point_hit_count);
3198 step_action = StepIn;
3199 break_point_hit_count = 0;
3200 v8::Handle<v8::Value> argv_2[argc] = { v8::Number::New(isolate, 2) };
3201 foo->Call(env->Global(), argc, argv_2);
3202 CHECK_EQ(5, break_point_hit_count);
3205 step_action = StepIn;
3206 break_point_hit_count = 0;
3207 v8::Handle<v8::Value> argv_3[argc] = { v8::Number::New(isolate, 3) };
3208 foo->Call(env->Global(), argc, argv_3);
3209 CHECK_EQ(7, break_point_hit_count);
3211 // Get rid of the debug event listener.
3212 v8::Debug::SetDebugEventListener(NULL);
3213 CheckDebuggerUnloaded();
3217 TEST(DebugStepWhile) {
3218 DebugLocalContext env;
3219 v8::Isolate* isolate = env->GetIsolate();
3220 v8::HandleScope scope(isolate);
3222 // Register a debug event listener which steps and counts.
3223 v8::Debug::SetDebugEventListener(DebugEventStep);
3225 // Create a function for testing stepping. Run it to allow it to get
3228 const char* src = "function foo(x) { "
3235 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3236 SetBreakPoint(foo, 8); // "var a = 0;"
3238 // Looping 0 times. We still should break at the while-condition once.
3239 step_action = StepIn;
3240 break_point_hit_count = 0;
3241 v8::Handle<v8::Value> argv_0[argc] = { v8::Number::New(isolate, 0) };
3242 foo->Call(env->Global(), argc, argv_0);
3243 CHECK_EQ(3, break_point_hit_count);
3245 // Looping 10 times.
3246 step_action = StepIn;
3247 break_point_hit_count = 0;
3248 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
3249 foo->Call(env->Global(), argc, argv_10);
3250 CHECK_EQ(23, break_point_hit_count);
3252 // Looping 100 times.
3253 step_action = StepIn;
3254 break_point_hit_count = 0;
3255 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
3256 foo->Call(env->Global(), argc, argv_100);
3257 CHECK_EQ(203, break_point_hit_count);
3259 // Get rid of the debug event listener.
3260 v8::Debug::SetDebugEventListener(NULL);
3261 CheckDebuggerUnloaded();
3265 TEST(DebugStepDoWhile) {
3266 DebugLocalContext env;
3267 v8::Isolate* isolate = env->GetIsolate();
3268 v8::HandleScope scope(isolate);
3270 // Register a debug event listener which steps and counts.
3271 v8::Debug::SetDebugEventListener(DebugEventStep);
3273 // Create a function for testing stepping. Run it to allow it to get
3276 const char* src = "function foo(x) { "
3283 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3284 SetBreakPoint(foo, 8); // "var a = 0;"
3286 // Looping 10 times.
3287 step_action = StepIn;
3288 break_point_hit_count = 0;
3289 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
3290 foo->Call(env->Global(), argc, argv_10);
3291 CHECK_EQ(22, break_point_hit_count);
3293 // Looping 100 times.
3294 step_action = StepIn;
3295 break_point_hit_count = 0;
3296 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
3297 foo->Call(env->Global(), argc, argv_100);
3298 CHECK_EQ(202, break_point_hit_count);
3300 // Get rid of the debug event listener.
3301 v8::Debug::SetDebugEventListener(NULL);
3302 CheckDebuggerUnloaded();
3306 TEST(DebugStepFor) {
3307 DebugLocalContext env;
3308 v8::Isolate* isolate = env->GetIsolate();
3309 v8::HandleScope scope(isolate);
3311 // Register a debug event listener which steps and counts.
3312 v8::Debug::SetDebugEventListener(DebugEventStep);
3314 // Create a function for testing stepping. Run it to allow it to get
3317 const char* src = "function foo(x) { "
3319 " for (i = 0; i < x; i++) {"
3323 "a=0; b=0; i=0; foo()";
3324 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3326 SetBreakPoint(foo, 8); // "a = 1;"
3328 // Looping 10 times.
3329 step_action = StepIn;
3330 break_point_hit_count = 0;
3331 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
3332 foo->Call(env->Global(), argc, argv_10);
3333 CHECK_EQ(23, break_point_hit_count);
3335 // Looping 100 times.
3336 step_action = StepIn;
3337 break_point_hit_count = 0;
3338 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
3339 foo->Call(env->Global(), argc, argv_100);
3340 CHECK_EQ(203, break_point_hit_count);
3342 // Get rid of the debug event listener.
3343 v8::Debug::SetDebugEventListener(NULL);
3344 CheckDebuggerUnloaded();
3348 TEST(DebugStepForContinue) {
3349 DebugLocalContext env;
3350 v8::Isolate* isolate = env->GetIsolate();
3351 v8::HandleScope scope(isolate);
3353 // Register a debug event listener which steps and counts.
3354 v8::Debug::SetDebugEventListener(DebugEventStep);
3356 // Create a function for testing stepping. Run it to allow it to get
3359 const char* src = "function foo(x) { "
3363 " for (var i = 0; i < x; i++) {"
3365 " if (a % 2 == 0) continue;"
3372 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3373 v8::Handle<v8::Value> result;
3374 SetBreakPoint(foo, 8); // "var a = 0;"
3376 // Each loop generates 4 or 5 steps depending on whether a is equal.
3378 // Looping 10 times.
3379 step_action = StepIn;
3380 break_point_hit_count = 0;
3381 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
3382 result = foo->Call(env->Global(), argc, argv_10);
3383 CHECK_EQ(5, result->Int32Value());
3384 CHECK_EQ(52, break_point_hit_count);
3386 // Looping 100 times.
3387 step_action = StepIn;
3388 break_point_hit_count = 0;
3389 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
3390 result = foo->Call(env->Global(), argc, argv_100);
3391 CHECK_EQ(50, result->Int32Value());
3392 CHECK_EQ(457, break_point_hit_count);
3394 // Get rid of the debug event listener.
3395 v8::Debug::SetDebugEventListener(NULL);
3396 CheckDebuggerUnloaded();
3400 TEST(DebugStepForBreak) {
3401 DebugLocalContext env;
3402 v8::Isolate* isolate = env->GetIsolate();
3403 v8::HandleScope scope(isolate);
3405 // Register a debug event listener which steps and counts.
3406 v8::Debug::SetDebugEventListener(DebugEventStep);
3408 // Create a function for testing stepping. Run it to allow it to get
3411 const char* src = "function foo(x) { "
3415 " for (var i = 0; i < 1000; i++) {"
3417 " if (a == x) break;"
3424 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3425 v8::Handle<v8::Value> result;
3426 SetBreakPoint(foo, 8); // "var a = 0;"
3428 // Each loop generates 5 steps except for the last (when break is executed)
3429 // which only generates 4.
3431 // Looping 10 times.
3432 step_action = StepIn;
3433 break_point_hit_count = 0;
3434 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
3435 result = foo->Call(env->Global(), argc, argv_10);
3436 CHECK_EQ(9, result->Int32Value());
3437 CHECK_EQ(55, break_point_hit_count);
3439 // Looping 100 times.
3440 step_action = StepIn;
3441 break_point_hit_count = 0;
3442 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
3443 result = foo->Call(env->Global(), argc, argv_100);
3444 CHECK_EQ(99, result->Int32Value());
3445 CHECK_EQ(505, break_point_hit_count);
3447 // Get rid of the debug event listener.
3448 v8::Debug::SetDebugEventListener(NULL);
3449 CheckDebuggerUnloaded();
3453 TEST(DebugStepForIn) {
3454 DebugLocalContext env;
3455 v8::HandleScope scope(env->GetIsolate());
3457 // Register a debug event listener which steps and counts.
3458 v8::Debug::SetDebugEventListener(DebugEventStep);
3460 // Create a function for testing stepping. Run it to allow it to get
3462 v8::Local<v8::Function> foo;
3463 const char* src_1 = "function foo() { "
3470 foo = CompileFunction(&env, src_1, "foo");
3471 SetBreakPoint(foo, 0); // "var a = ..."
3473 step_action = StepIn;
3474 break_point_hit_count = 0;
3475 foo->Call(env->Global(), 0, NULL);
3476 CHECK_EQ(6, break_point_hit_count);
3478 // Create a function for testing stepping. Run it to allow it to get
3480 const char* src_2 = "function foo() { "
3481 " var a = {a:[1, 2, 3]};"
3487 foo = CompileFunction(&env, src_2, "foo");
3488 SetBreakPoint(foo, 0); // "var a = ..."
3490 step_action = StepIn;
3491 break_point_hit_count = 0;
3492 foo->Call(env->Global(), 0, NULL);
3493 CHECK_EQ(8, break_point_hit_count);
3495 // Get rid of the debug event listener.
3496 v8::Debug::SetDebugEventListener(NULL);
3497 CheckDebuggerUnloaded();
3501 TEST(DebugStepWith) {
3502 DebugLocalContext env;
3503 v8::HandleScope scope(env->GetIsolate());
3505 // Register a debug event listener which steps and counts.
3506 v8::Debug::SetDebugEventListener(DebugEventStep);
3508 // Create a function for testing stepping. Run it to allow it to get
3510 const char* src = "function foo(x) { "
3516 env->Global()->Set(v8::String::NewFromUtf8(env->GetIsolate(), "b"),
3517 v8::Object::New(env->GetIsolate()));
3518 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3519 v8::Handle<v8::Value> result;
3520 SetBreakPoint(foo, 8); // "var a = {};"
3522 step_action = StepIn;
3523 break_point_hit_count = 0;
3524 foo->Call(env->Global(), 0, NULL);
3525 CHECK_EQ(4, break_point_hit_count);
3527 // Get rid of the debug event listener.
3528 v8::Debug::SetDebugEventListener(NULL);
3529 CheckDebuggerUnloaded();
3533 TEST(DebugConditional) {
3534 DebugLocalContext env;
3535 v8::Isolate* isolate = env->GetIsolate();
3536 v8::HandleScope scope(isolate);
3538 // Register a debug event listener which steps and counts.
3539 v8::Debug::SetDebugEventListener(DebugEventStep);
3541 // Create a function for testing stepping. Run it to allow it to get
3543 const char* src = "function foo(x) { "
3549 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3550 SetBreakPoint(foo, 0); // "var a;"
3552 step_action = StepIn;
3553 break_point_hit_count = 0;
3554 foo->Call(env->Global(), 0, NULL);
3555 CHECK_EQ(5, break_point_hit_count);
3557 step_action = StepIn;
3558 break_point_hit_count = 0;
3560 v8::Handle<v8::Value> argv_true[argc] = { v8::True(isolate) };
3561 foo->Call(env->Global(), argc, argv_true);
3562 CHECK_EQ(5, break_point_hit_count);
3564 // Get rid of the debug event listener.
3565 v8::Debug::SetDebugEventListener(NULL);
3566 CheckDebuggerUnloaded();
3570 TEST(StepInOutSimple) {
3571 DebugLocalContext env;
3572 v8::HandleScope scope(env->GetIsolate());
3574 // Create a function for checking the function when hitting a break point.
3575 frame_function_name = CompileFunction(&env,
3576 frame_function_name_source,
3577 "frame_function_name");
3579 // Register a debug event listener which steps and counts.
3580 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3582 // Create a function for testing stepping. Run it to allow it to get
3584 const char* src = "function a() {b();c();}; "
3585 "function b() {c();}; "
3588 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3589 SetBreakPoint(a, 0);
3591 // Step through invocation of a with step in.
3592 step_action = StepIn;
3593 break_point_hit_count = 0;
3594 expected_step_sequence = "abcbaca";
3595 a->Call(env->Global(), 0, NULL);
3596 CHECK_EQ(StrLength(expected_step_sequence),
3597 break_point_hit_count);
3599 // Step through invocation of a with step next.
3600 step_action = StepNext;
3601 break_point_hit_count = 0;
3602 expected_step_sequence = "aaa";
3603 a->Call(env->Global(), 0, NULL);
3604 CHECK_EQ(StrLength(expected_step_sequence),
3605 break_point_hit_count);
3607 // Step through invocation of a with step out.
3608 step_action = StepOut;
3609 break_point_hit_count = 0;
3610 expected_step_sequence = "a";
3611 a->Call(env->Global(), 0, NULL);
3612 CHECK_EQ(StrLength(expected_step_sequence),
3613 break_point_hit_count);
3615 // Get rid of the debug event listener.
3616 v8::Debug::SetDebugEventListener(NULL);
3617 CheckDebuggerUnloaded();
3621 TEST(StepInOutTree) {
3622 DebugLocalContext env;
3623 v8::HandleScope scope(env->GetIsolate());
3625 // Create a function for checking the function when hitting a break point.
3626 frame_function_name = CompileFunction(&env,
3627 frame_function_name_source,
3628 "frame_function_name");
3630 // Register a debug event listener which steps and counts.
3631 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3633 // Create a function for testing stepping. Run it to allow it to get
3635 const char* src = "function a() {b(c(d()),d());c(d());d()}; "
3636 "function b(x,y) {c();}; "
3637 "function c(x) {}; "
3639 "a(); b(); c(); d()";
3640 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3641 SetBreakPoint(a, 0);
3643 // Step through invocation of a with step in.
3644 step_action = StepIn;
3645 break_point_hit_count = 0;
3646 expected_step_sequence = "adacadabcbadacada";
3647 a->Call(env->Global(), 0, NULL);
3648 CHECK_EQ(StrLength(expected_step_sequence),
3649 break_point_hit_count);
3651 // Step through invocation of a with step next.
3652 step_action = StepNext;
3653 break_point_hit_count = 0;
3654 expected_step_sequence = "aaaa";
3655 a->Call(env->Global(), 0, NULL);
3656 CHECK_EQ(StrLength(expected_step_sequence),
3657 break_point_hit_count);
3659 // Step through invocation of a with step out.
3660 step_action = StepOut;
3661 break_point_hit_count = 0;
3662 expected_step_sequence = "a";
3663 a->Call(env->Global(), 0, NULL);
3664 CHECK_EQ(StrLength(expected_step_sequence),
3665 break_point_hit_count);
3667 // Get rid of the debug event listener.
3668 v8::Debug::SetDebugEventListener(NULL);
3669 CheckDebuggerUnloaded(true);
3673 TEST(StepInOutBranch) {
3674 DebugLocalContext env;
3675 v8::HandleScope scope(env->GetIsolate());
3677 // Create a function for checking the function when hitting a break point.
3678 frame_function_name = CompileFunction(&env,
3679 frame_function_name_source,
3680 "frame_function_name");
3682 // Register a debug event listener which steps and counts.
3683 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3685 // Create a function for testing stepping. Run it to allow it to get
3687 const char* src = "function a() {b(false);c();}; "
3688 "function b(x) {if(x){c();};}; "
3691 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3692 SetBreakPoint(a, 0);
3694 // Step through invocation of a.
3695 step_action = StepIn;
3696 break_point_hit_count = 0;
3697 expected_step_sequence = "abbaca";
3698 a->Call(env->Global(), 0, NULL);
3699 CHECK_EQ(StrLength(expected_step_sequence),
3700 break_point_hit_count);
3702 // Get rid of the debug event listener.
3703 v8::Debug::SetDebugEventListener(NULL);
3704 CheckDebuggerUnloaded();
3708 // Test that step in does not step into native functions.
3709 TEST(DebugStepNatives) {
3710 DebugLocalContext env;
3711 v8::HandleScope scope(env->GetIsolate());
3713 // Create a function for testing stepping.
3714 v8::Local<v8::Function> foo = CompileFunction(
3716 "function foo(){debugger;Math.sin(1);}",
3719 // Register a debug event listener which steps and counts.
3720 v8::Debug::SetDebugEventListener(DebugEventStep);
3722 step_action = StepIn;
3723 break_point_hit_count = 0;
3724 foo->Call(env->Global(), 0, NULL);
3726 // With stepping all break locations are hit.
3727 CHECK_EQ(3, break_point_hit_count);
3729 v8::Debug::SetDebugEventListener(NULL);
3730 CheckDebuggerUnloaded();
3732 // Register a debug event listener which just counts.
3733 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3735 break_point_hit_count = 0;
3736 foo->Call(env->Global(), 0, NULL);
3738 // Without stepping only active break points are hit.
3739 CHECK_EQ(1, break_point_hit_count);
3741 v8::Debug::SetDebugEventListener(NULL);
3742 CheckDebuggerUnloaded();
3746 // Test that step in works with function.apply.
3747 TEST(DebugStepFunctionApply) {
3748 DebugLocalContext env;
3749 v8::HandleScope scope(env->GetIsolate());
3751 // Create a function for testing stepping.
3752 v8::Local<v8::Function> foo = CompileFunction(
3754 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3755 "function foo(){ debugger; bar.apply(this, [1,2,3]); }",
3758 // Register a debug event listener which steps and counts.
3759 v8::Debug::SetDebugEventListener(DebugEventStep);
3761 step_action = StepIn;
3762 break_point_hit_count = 0;
3763 foo->Call(env->Global(), 0, NULL);
3765 // With stepping all break locations are hit.
3766 CHECK_EQ(7, break_point_hit_count);
3768 v8::Debug::SetDebugEventListener(NULL);
3769 CheckDebuggerUnloaded();
3771 // Register a debug event listener which just counts.
3772 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3774 break_point_hit_count = 0;
3775 foo->Call(env->Global(), 0, NULL);
3777 // Without stepping only the debugger statement is hit.
3778 CHECK_EQ(1, break_point_hit_count);
3780 v8::Debug::SetDebugEventListener(NULL);
3781 CheckDebuggerUnloaded();
3785 // Test that step in works with function.call.
3786 TEST(DebugStepFunctionCall) {
3787 DebugLocalContext env;
3788 v8::Isolate* isolate = env->GetIsolate();
3789 v8::HandleScope scope(isolate);
3791 // Create a function for testing stepping.
3792 v8::Local<v8::Function> foo = CompileFunction(
3794 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3795 "function foo(a){ debugger;"
3797 " bar.call(this, 1, 2, 3);"
3799 " bar.call(this, 0);"
3804 // Register a debug event listener which steps and counts.
3805 v8::Debug::SetDebugEventListener(DebugEventStep);
3806 step_action = StepIn;
3808 // Check stepping where the if condition in bar is false.
3809 break_point_hit_count = 0;
3810 foo->Call(env->Global(), 0, NULL);
3811 CHECK_EQ(6, break_point_hit_count);
3813 // Check stepping where the if condition in bar is true.
3814 break_point_hit_count = 0;
3816 v8::Handle<v8::Value> argv[argc] = { v8::True(isolate) };
3817 foo->Call(env->Global(), argc, argv);
3818 CHECK_EQ(8, break_point_hit_count);
3820 v8::Debug::SetDebugEventListener(NULL);
3821 CheckDebuggerUnloaded();
3823 // Register a debug event listener which just counts.
3824 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3826 break_point_hit_count = 0;
3827 foo->Call(env->Global(), 0, NULL);
3829 // Without stepping only the debugger statement is hit.
3830 CHECK_EQ(1, break_point_hit_count);
3832 v8::Debug::SetDebugEventListener(NULL);
3833 CheckDebuggerUnloaded();
3837 // Tests that breakpoint will be hit if it's set in script.
3838 TEST(PauseInScript) {
3839 DebugLocalContext env;
3840 v8::HandleScope scope(env->GetIsolate());
3843 // Register a debug event listener which counts.
3844 v8::Debug::SetDebugEventListener(DebugEventCounter);
3846 // Create a script that returns a function.
3847 const char* src = "(function (evt) {})";
3848 const char* script_name = "StepInHandlerTest";
3850 // Set breakpoint in the script.
3851 SetScriptBreakPointByNameFromJS(env->GetIsolate(), script_name, 0, -1);
3852 break_point_hit_count = 0;
3854 v8::ScriptOrigin origin(
3855 v8::String::NewFromUtf8(env->GetIsolate(), script_name),
3856 v8::Integer::New(env->GetIsolate(), 0));
3857 v8::Handle<v8::Script> script = v8::Script::Compile(
3858 v8::String::NewFromUtf8(env->GetIsolate(), src), &origin);
3859 v8::Local<v8::Value> r = script->Run();
3861 CHECK(r->IsFunction());
3862 CHECK_EQ(1, break_point_hit_count);
3864 // Get rid of the debug event listener.
3865 v8::Debug::SetDebugEventListener(NULL);
3866 CheckDebuggerUnloaded();
3870 // Test break on exceptions. For each exception break combination the number
3871 // of debug event exception callbacks and message callbacks are collected. The
3872 // number of debug event exception callbacks are used to check that the
3873 // debugger is called correctly and the number of message callbacks is used to
3874 // check that uncaught exceptions are still returned even if there is a break
3876 TEST(BreakOnException) {
3877 DebugLocalContext env;
3878 v8::HandleScope scope(env->GetIsolate());
3881 // Create functions for testing break on exception.
3882 CompileFunction(&env, "function throws(){throw 1;}", "throws");
3883 v8::Local<v8::Function> caught =
3884 CompileFunction(&env,
3885 "function caught(){try {throws();} catch(e) {};}",
3887 v8::Local<v8::Function> notCaught =
3888 CompileFunction(&env, "function notCaught(){throws();}", "notCaught");
3890 v8::V8::AddMessageListener(MessageCallbackCount);
3891 v8::Debug::SetDebugEventListener(DebugEventCounter);
3893 // Initial state should be no break on exceptions.
3894 DebugEventCounterClear();
3895 MessageCallbackCountClear();
3896 caught->Call(env->Global(), 0, NULL);
3897 CHECK_EQ(0, exception_hit_count);
3898 CHECK_EQ(0, uncaught_exception_hit_count);
3899 CHECK_EQ(0, message_callback_count);
3900 notCaught->Call(env->Global(), 0, NULL);
3901 CHECK_EQ(0, exception_hit_count);
3902 CHECK_EQ(0, uncaught_exception_hit_count);
3903 CHECK_EQ(1, message_callback_count);
3905 // No break on exception
3906 DebugEventCounterClear();
3907 MessageCallbackCountClear();
3908 ChangeBreakOnException(false, false);
3909 caught->Call(env->Global(), 0, NULL);
3910 CHECK_EQ(0, exception_hit_count);
3911 CHECK_EQ(0, uncaught_exception_hit_count);
3912 CHECK_EQ(0, message_callback_count);
3913 notCaught->Call(env->Global(), 0, NULL);
3914 CHECK_EQ(0, exception_hit_count);
3915 CHECK_EQ(0, uncaught_exception_hit_count);
3916 CHECK_EQ(1, message_callback_count);
3918 // Break on uncaught exception
3919 DebugEventCounterClear();
3920 MessageCallbackCountClear();
3921 ChangeBreakOnException(false, true);
3922 caught->Call(env->Global(), 0, NULL);
3923 CHECK_EQ(0, exception_hit_count);
3924 CHECK_EQ(0, uncaught_exception_hit_count);
3925 CHECK_EQ(0, message_callback_count);
3926 notCaught->Call(env->Global(), 0, NULL);
3927 CHECK_EQ(1, exception_hit_count);
3928 CHECK_EQ(1, uncaught_exception_hit_count);
3929 CHECK_EQ(1, message_callback_count);
3931 // Break on exception and uncaught exception
3932 DebugEventCounterClear();
3933 MessageCallbackCountClear();
3934 ChangeBreakOnException(true, true);
3935 caught->Call(env->Global(), 0, NULL);
3936 CHECK_EQ(1, exception_hit_count);
3937 CHECK_EQ(0, uncaught_exception_hit_count);
3938 CHECK_EQ(0, message_callback_count);
3939 notCaught->Call(env->Global(), 0, NULL);
3940 CHECK_EQ(2, exception_hit_count);
3941 CHECK_EQ(1, uncaught_exception_hit_count);
3942 CHECK_EQ(1, message_callback_count);
3944 // Break on exception
3945 DebugEventCounterClear();
3946 MessageCallbackCountClear();
3947 ChangeBreakOnException(true, false);
3948 caught->Call(env->Global(), 0, NULL);
3949 CHECK_EQ(1, exception_hit_count);
3950 CHECK_EQ(0, uncaught_exception_hit_count);
3951 CHECK_EQ(0, message_callback_count);
3952 notCaught->Call(env->Global(), 0, NULL);
3953 CHECK_EQ(2, exception_hit_count);
3954 CHECK_EQ(1, uncaught_exception_hit_count);
3955 CHECK_EQ(1, message_callback_count);
3957 // No break on exception using JavaScript
3958 DebugEventCounterClear();
3959 MessageCallbackCountClear();
3960 ChangeBreakOnExceptionFromJS(env->GetIsolate(), false, false);
3961 caught->Call(env->Global(), 0, NULL);
3962 CHECK_EQ(0, exception_hit_count);
3963 CHECK_EQ(0, uncaught_exception_hit_count);
3964 CHECK_EQ(0, message_callback_count);
3965 notCaught->Call(env->Global(), 0, NULL);
3966 CHECK_EQ(0, exception_hit_count);
3967 CHECK_EQ(0, uncaught_exception_hit_count);
3968 CHECK_EQ(1, message_callback_count);
3970 // Break on uncaught exception using JavaScript
3971 DebugEventCounterClear();
3972 MessageCallbackCountClear();
3973 ChangeBreakOnExceptionFromJS(env->GetIsolate(), false, true);
3974 caught->Call(env->Global(), 0, NULL);
3975 CHECK_EQ(0, exception_hit_count);
3976 CHECK_EQ(0, uncaught_exception_hit_count);
3977 CHECK_EQ(0, message_callback_count);
3978 notCaught->Call(env->Global(), 0, NULL);
3979 CHECK_EQ(1, exception_hit_count);
3980 CHECK_EQ(1, uncaught_exception_hit_count);
3981 CHECK_EQ(1, message_callback_count);
3983 // Break on exception and uncaught exception using JavaScript
3984 DebugEventCounterClear();
3985 MessageCallbackCountClear();
3986 ChangeBreakOnExceptionFromJS(env->GetIsolate(), true, true);
3987 caught->Call(env->Global(), 0, NULL);
3988 CHECK_EQ(1, exception_hit_count);
3989 CHECK_EQ(0, message_callback_count);
3990 CHECK_EQ(0, uncaught_exception_hit_count);
3991 notCaught->Call(env->Global(), 0, NULL);
3992 CHECK_EQ(2, exception_hit_count);
3993 CHECK_EQ(1, uncaught_exception_hit_count);
3994 CHECK_EQ(1, message_callback_count);
3996 // Break on exception using JavaScript
3997 DebugEventCounterClear();
3998 MessageCallbackCountClear();
3999 ChangeBreakOnExceptionFromJS(env->GetIsolate(), true, false);
4000 caught->Call(env->Global(), 0, NULL);
4001 CHECK_EQ(1, exception_hit_count);
4002 CHECK_EQ(0, uncaught_exception_hit_count);
4003 CHECK_EQ(0, message_callback_count);
4004 notCaught->Call(env->Global(), 0, NULL);
4005 CHECK_EQ(2, exception_hit_count);
4006 CHECK_EQ(1, uncaught_exception_hit_count);
4007 CHECK_EQ(1, message_callback_count);
4009 v8::Debug::SetDebugEventListener(NULL);
4010 CheckDebuggerUnloaded();
4011 v8::V8::RemoveMessageListeners(MessageCallbackCount);
4015 TEST(EvalJSInDebugEventListenerOnNativeReThrownException) {
4016 DebugLocalContext env;
4017 v8::HandleScope scope(env->GetIsolate());
4020 // Create functions for testing break on exception.
4021 v8::Local<v8::Function> noThrowJS = CompileFunction(
4022 &env, "function noThrowJS(){var a=[1]; a.push(2); return a.length;}",
4025 debug_event_listener_callback = noThrowJS;
4026 debug_event_listener_callback_result = 2;
4028 v8::V8::AddMessageListener(MessageCallbackCount);
4029 v8::Debug::SetDebugEventListener(DebugEventCounter);
4030 // Break on uncaught exception
4031 ChangeBreakOnException(false, true);
4032 DebugEventCounterClear();
4033 MessageCallbackCountClear();
4035 // ReThrow native error
4037 v8::TryCatch tryCatch;
4038 env->GetIsolate()->ThrowException(v8::Exception::TypeError(
4039 v8::String::NewFromUtf8(env->GetIsolate(), "Type error")));
4040 CHECK(tryCatch.HasCaught());
4043 CHECK_EQ(1, exception_hit_count);
4044 CHECK_EQ(1, uncaught_exception_hit_count);
4045 CHECK_EQ(0, message_callback_count); // FIXME: Should it be 1 ?
4046 CHECK(!debug_event_listener_callback.IsEmpty());
4048 debug_event_listener_callback.Clear();
4052 // Test break on exception from compiler errors. When compiling using
4053 // v8::Script::Compile there is no JavaScript stack whereas when compiling using
4054 // eval there are JavaScript frames.
4055 TEST(BreakOnCompileException) {
4056 DebugLocalContext env;
4057 v8::HandleScope scope(env->GetIsolate());
4059 // For this test, we want to break on uncaught exceptions:
4060 ChangeBreakOnException(false, true);
4062 // Create a function for checking the function when hitting a break point.
4063 frame_count = CompileFunction(&env, frame_count_source, "frame_count");
4065 v8::V8::AddMessageListener(MessageCallbackCount);
4066 v8::Debug::SetDebugEventListener(DebugEventCounter);
4068 DebugEventCounterClear();
4069 MessageCallbackCountClear();
4071 // Check initial state.
4072 CHECK_EQ(0, exception_hit_count);
4073 CHECK_EQ(0, uncaught_exception_hit_count);
4074 CHECK_EQ(0, message_callback_count);
4075 CHECK_EQ(-1, last_js_stack_height);
4077 // Throws SyntaxError: Unexpected end of input
4078 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "+++"));
4079 CHECK_EQ(1, exception_hit_count);
4080 CHECK_EQ(1, uncaught_exception_hit_count);
4081 CHECK_EQ(1, message_callback_count);
4082 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
4084 // Throws SyntaxError: Unexpected identifier
4085 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "x x"));
4086 CHECK_EQ(2, exception_hit_count);
4087 CHECK_EQ(2, uncaught_exception_hit_count);
4088 CHECK_EQ(2, message_callback_count);
4089 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
4091 // Throws SyntaxError: Unexpected end of input
4092 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "eval('+++')"))
4094 CHECK_EQ(3, exception_hit_count);
4095 CHECK_EQ(3, uncaught_exception_hit_count);
4096 CHECK_EQ(3, message_callback_count);
4097 CHECK_EQ(1, last_js_stack_height);
4099 // Throws SyntaxError: Unexpected identifier
4100 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "eval('x x')"))
4102 CHECK_EQ(4, exception_hit_count);
4103 CHECK_EQ(4, uncaught_exception_hit_count);
4104 CHECK_EQ(4, message_callback_count);
4105 CHECK_EQ(1, last_js_stack_height);
4109 TEST(StepWithException) {
4110 DebugLocalContext env;
4111 v8::HandleScope scope(env->GetIsolate());
4113 // For this test, we want to break on uncaught exceptions:
4114 ChangeBreakOnException(false, true);
4116 // Create a function for checking the function when hitting a break point.
4117 frame_function_name = CompileFunction(&env,
4118 frame_function_name_source,
4119 "frame_function_name");
4121 // Register a debug event listener which steps and counts.
4122 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
4124 // Create functions for testing stepping.
4125 const char* src = "function a() { n(); }; "
4126 "function b() { c(); }; "
4127 "function c() { n(); }; "
4128 "function d() { x = 1; try { e(); } catch(x) { x = 2; } }; "
4129 "function e() { n(); }; "
4130 "function f() { x = 1; try { g(); } catch(x) { x = 2; } }; "
4131 "function g() { h(); }; "
4132 "function h() { x = 1; throw 1; }; ";
4134 // Step through invocation of a.
4135 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
4136 SetBreakPoint(a, 0);
4137 step_action = StepIn;
4138 break_point_hit_count = 0;
4139 expected_step_sequence = "aa";
4140 a->Call(env->Global(), 0, NULL);
4141 CHECK_EQ(StrLength(expected_step_sequence),
4142 break_point_hit_count);
4144 // Step through invocation of b + c.
4145 v8::Local<v8::Function> b = CompileFunction(&env, src, "b");
4146 SetBreakPoint(b, 0);
4147 step_action = StepIn;
4148 break_point_hit_count = 0;
4149 expected_step_sequence = "bcc";
4150 b->Call(env->Global(), 0, NULL);
4151 CHECK_EQ(StrLength(expected_step_sequence),
4152 break_point_hit_count);
4153 // Step through invocation of d + e.
4154 v8::Local<v8::Function> d = CompileFunction(&env, src, "d");
4155 SetBreakPoint(d, 0);
4156 ChangeBreakOnException(false, true);
4157 step_action = StepIn;
4158 break_point_hit_count = 0;
4159 expected_step_sequence = "ddedd";
4160 d->Call(env->Global(), 0, NULL);
4161 CHECK_EQ(StrLength(expected_step_sequence),
4162 break_point_hit_count);
4164 // Step through invocation of d + e now with break on caught exceptions.
4165 ChangeBreakOnException(true, true);
4166 step_action = StepIn;
4167 break_point_hit_count = 0;
4168 expected_step_sequence = "ddeedd";
4169 d->Call(env->Global(), 0, NULL);
4170 CHECK_EQ(StrLength(expected_step_sequence),
4171 break_point_hit_count);
4173 // Step through invocation of f + g + h.
4174 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
4175 SetBreakPoint(f, 0);
4176 ChangeBreakOnException(false, true);
4177 step_action = StepIn;
4178 break_point_hit_count = 0;
4179 expected_step_sequence = "ffghhff";
4180 f->Call(env->Global(), 0, NULL);
4181 CHECK_EQ(StrLength(expected_step_sequence),
4182 break_point_hit_count);
4184 // Step through invocation of f + g + h now with break on caught exceptions.
4185 ChangeBreakOnException(true, true);
4186 step_action = StepIn;
4187 break_point_hit_count = 0;
4188 expected_step_sequence = "ffghhhff";
4189 f->Call(env->Global(), 0, NULL);
4190 CHECK_EQ(StrLength(expected_step_sequence),
4191 break_point_hit_count);
4193 // Get rid of the debug event listener.
4194 v8::Debug::SetDebugEventListener(NULL);
4195 CheckDebuggerUnloaded();
4200 i::FLAG_stress_compaction = false;
4202 i::FLAG_verify_heap = true;
4204 DebugLocalContext env;
4205 v8::Isolate* isolate = env->GetIsolate();
4206 v8::HandleScope scope(isolate);
4208 // Register a debug event listener which sets the break flag and counts.
4209 v8::Debug::SetDebugEventListener(DebugEventBreak);
4211 // Create a function for testing stepping.
4212 const char* src = "function f0() {}"
4213 "function f1(x1) {}"
4214 "function f2(x1,x2) {}"
4215 "function f3(x1,x2,x3) {}";
4216 v8::Local<v8::Function> f0 = CompileFunction(&env, src, "f0");
4217 v8::Local<v8::Function> f1 = CompileFunction(&env, src, "f1");
4218 v8::Local<v8::Function> f2 = CompileFunction(&env, src, "f2");
4219 v8::Local<v8::Function> f3 = CompileFunction(&env, src, "f3");
4221 // Call the function to make sure it is compiled.
4222 v8::Handle<v8::Value> argv[] = { v8::Number::New(isolate, 1),
4223 v8::Number::New(isolate, 1),
4224 v8::Number::New(isolate, 1),
4225 v8::Number::New(isolate, 1) };
4227 // Call all functions to make sure that they are compiled.
4228 f0->Call(env->Global(), 0, NULL);
4229 f1->Call(env->Global(), 0, NULL);
4230 f2->Call(env->Global(), 0, NULL);
4231 f3->Call(env->Global(), 0, NULL);
4233 // Set the debug break flag.
4234 v8::Debug::DebugBreak(env->GetIsolate());
4235 CHECK(v8::Debug::CheckDebugBreak(env->GetIsolate()));
4237 // Call all functions with different argument count.
4238 break_point_hit_count = 0;
4239 for (unsigned int i = 0; i < arraysize(argv); i++) {
4240 f0->Call(env->Global(), i, argv);
4241 f1->Call(env->Global(), i, argv);
4242 f2->Call(env->Global(), i, argv);
4243 f3->Call(env->Global(), i, argv);
4246 // One break for each function called.
4247 CHECK_EQ(4 * arraysize(argv), break_point_hit_count);
4249 // Get rid of the debug event listener.
4250 v8::Debug::SetDebugEventListener(NULL);
4251 CheckDebuggerUnloaded();
4255 // Test to ensure that JavaScript code keeps running while the debug break
4256 // through the stack limit flag is set but breaks are disabled.
4257 TEST(DisableBreak) {
4258 DebugLocalContext env;
4259 v8::HandleScope scope(env->GetIsolate());
4261 // Register a debug event listener which sets the break flag and counts.
4262 v8::Debug::SetDebugEventListener(DebugEventCounter);
4264 // Create a function for testing stepping.
4265 const char* src = "function f() {g()};function g(){i=0; while(i<10){i++}}";
4266 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
4268 // Set, test and cancel debug break.
4269 v8::Debug::DebugBreak(env->GetIsolate());
4270 CHECK(v8::Debug::CheckDebugBreak(env->GetIsolate()));
4271 v8::Debug::CancelDebugBreak(env->GetIsolate());
4272 CHECK(!v8::Debug::CheckDebugBreak(env->GetIsolate()));
4274 // Set the debug break flag.
4275 v8::Debug::DebugBreak(env->GetIsolate());
4277 // Call all functions with different argument count.
4278 break_point_hit_count = 0;
4279 f->Call(env->Global(), 0, NULL);
4280 CHECK_EQ(1, break_point_hit_count);
4283 v8::Debug::DebugBreak(env->GetIsolate());
4284 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
4285 v8::internal::DisableBreak disable_break(isolate->debug(), true);
4286 f->Call(env->Global(), 0, NULL);
4287 CHECK_EQ(1, break_point_hit_count);
4290 f->Call(env->Global(), 0, NULL);
4291 CHECK_EQ(2, break_point_hit_count);
4293 // Get rid of the debug event listener.
4294 v8::Debug::SetDebugEventListener(NULL);
4295 CheckDebuggerUnloaded();
4298 static const char* kSimpleExtensionSource =
4303 // http://crbug.com/28933
4304 // Test that debug break is disabled when bootstrapper is active.
4305 TEST(NoBreakWhenBootstrapping) {
4306 v8::Isolate* isolate = CcTest::isolate();
4307 v8::HandleScope scope(isolate);
4309 // Register a debug event listener which sets the break flag and counts.
4310 v8::Debug::SetDebugEventListener(DebugEventCounter);
4312 // Set the debug break flag.
4313 v8::Debug::DebugBreak(isolate);
4314 break_point_hit_count = 0;
4316 // Create a context with an extension to make sure that some JavaScript
4317 // code is executed during bootstrapping.
4318 v8::RegisterExtension(new v8::Extension("simpletest",
4319 kSimpleExtensionSource));
4320 const char* extension_names[] = { "simpletest" };
4321 v8::ExtensionConfiguration extensions(1, extension_names);
4322 v8::HandleScope handle_scope(isolate);
4323 v8::Context::New(isolate, &extensions);
4325 // Check that no DebugBreak events occured during the context creation.
4326 CHECK_EQ(0, break_point_hit_count);
4328 // Get rid of the debug event listener.
4329 v8::Debug::SetDebugEventListener(NULL);
4330 CheckDebuggerUnloaded();
4334 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
4335 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
4336 result->Set(v8::Integer::New(info.GetIsolate(), 0),
4337 v8::String::NewFromUtf8(info.GetIsolate(), "a"));
4338 result->Set(v8::Integer::New(info.GetIsolate(), 1),
4339 v8::String::NewFromUtf8(info.GetIsolate(), "b"));
4340 result->Set(v8::Integer::New(info.GetIsolate(), 2),
4341 v8::String::NewFromUtf8(info.GetIsolate(), "c"));
4342 info.GetReturnValue().Set(result);
4346 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
4347 v8::Isolate* isolate = info.GetIsolate();
4348 v8::Handle<v8::Array> result = v8::Array::New(isolate, 2);
4349 result->Set(v8::Integer::New(isolate, 0), v8::Number::New(isolate, 1));
4350 result->Set(v8::Integer::New(isolate, 1), v8::Number::New(isolate, 10));
4351 info.GetReturnValue().Set(result);
4355 static void NamedGetter(v8::Local<v8::String> name,
4356 const v8::PropertyCallbackInfo<v8::Value>& info) {
4357 v8::String::Utf8Value n(name);
4358 if (strcmp(*n, "a") == 0) {
4359 info.GetReturnValue().Set(v8::String::NewFromUtf8(info.GetIsolate(), "AA"));
4361 } else if (strcmp(*n, "b") == 0) {
4362 info.GetReturnValue().Set(v8::String::NewFromUtf8(info.GetIsolate(), "BB"));
4364 } else if (strcmp(*n, "c") == 0) {
4365 info.GetReturnValue().Set(v8::String::NewFromUtf8(info.GetIsolate(), "CC"));
4368 info.GetReturnValue().SetUndefined();
4371 info.GetReturnValue().Set(name);
4375 static void IndexedGetter(uint32_t index,
4376 const v8::PropertyCallbackInfo<v8::Value>& info) {
4377 info.GetReturnValue().Set(static_cast<double>(index + 1));
4381 TEST(InterceptorPropertyMirror) {
4382 // Create a V8 environment with debug access.
4383 DebugLocalContext env;
4384 v8::Isolate* isolate = env->GetIsolate();
4385 v8::HandleScope scope(isolate);
4388 // Create object with named interceptor.
4389 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
4390 named->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
4392 v8::String::NewFromUtf8(isolate, "intercepted_named"),
4393 named->NewInstance());
4395 // Create object with indexed interceptor.
4396 v8::Handle<v8::ObjectTemplate> indexed = v8::ObjectTemplate::New(isolate);
4397 indexed->SetIndexedPropertyHandler(IndexedGetter,
4403 v8::String::NewFromUtf8(isolate, "intercepted_indexed"),
4404 indexed->NewInstance());
4406 // Create object with both named and indexed interceptor.
4407 v8::Handle<v8::ObjectTemplate> both = v8::ObjectTemplate::New(isolate);
4408 both->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
4409 both->SetIndexedPropertyHandler(IndexedGetter, NULL, NULL, NULL, IndexedEnum);
4411 v8::String::NewFromUtf8(isolate, "intercepted_both"),
4412 both->NewInstance());
4414 // Get mirrors for the three objects with interceptor.
4416 "var named_mirror = debug.MakeMirror(intercepted_named);"
4417 "var indexed_mirror = debug.MakeMirror(intercepted_indexed);"
4418 "var both_mirror = debug.MakeMirror(intercepted_both)");
4420 "named_mirror instanceof debug.ObjectMirror")->BooleanValue());
4422 "indexed_mirror instanceof debug.ObjectMirror")->BooleanValue());
4424 "both_mirror instanceof debug.ObjectMirror")->BooleanValue());
4426 // Get the property names from the interceptors
4428 "named_names = named_mirror.propertyNames();"
4429 "indexed_names = indexed_mirror.propertyNames();"
4430 "both_names = both_mirror.propertyNames()");
4431 CHECK_EQ(3, CompileRun("named_names.length")->Int32Value());
4432 CHECK_EQ(2, CompileRun("indexed_names.length")->Int32Value());
4433 CHECK_EQ(5, CompileRun("both_names.length")->Int32Value());
4435 // Check the expected number of properties.
4437 source = "named_mirror.properties().length";
4438 CHECK_EQ(3, CompileRun(source)->Int32Value());
4440 source = "indexed_mirror.properties().length";
4441 CHECK_EQ(2, CompileRun(source)->Int32Value());
4443 source = "both_mirror.properties().length";
4444 CHECK_EQ(5, CompileRun(source)->Int32Value());
4446 // 1 is PropertyKind.Named;
4447 source = "both_mirror.properties(1).length";
4448 CHECK_EQ(3, CompileRun(source)->Int32Value());
4450 // 2 is PropertyKind.Indexed;
4451 source = "both_mirror.properties(2).length";
4452 CHECK_EQ(2, CompileRun(source)->Int32Value());
4454 // 3 is PropertyKind.Named | PropertyKind.Indexed;
4455 source = "both_mirror.properties(3).length";
4456 CHECK_EQ(5, CompileRun(source)->Int32Value());
4458 // Get the interceptor properties for the object with only named interceptor.
4459 CompileRun("var named_values = named_mirror.properties()");
4461 // Check that the properties are interceptor properties.
4462 for (int i = 0; i < 3; i++) {
4463 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4465 "named_values[%d] instanceof debug.PropertyMirror", i);
4466 CHECK(CompileRun(buffer.start())->BooleanValue());
4468 SNPrintF(buffer, "named_values[%d].isNative()", i);
4469 CHECK(CompileRun(buffer.start())->BooleanValue());
4472 // Get the interceptor properties for the object with only indexed
4474 CompileRun("var indexed_values = indexed_mirror.properties()");
4476 // Check that the properties are interceptor properties.
4477 for (int i = 0; i < 2; i++) {
4478 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4480 "indexed_values[%d] instanceof debug.PropertyMirror", i);
4481 CHECK(CompileRun(buffer.start())->BooleanValue());
4484 // Get the interceptor properties for the object with both types of
4486 CompileRun("var both_values = both_mirror.properties()");
4488 // Check that the properties are interceptor properties.
4489 for (int i = 0; i < 5; i++) {
4490 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4491 SNPrintF(buffer, "both_values[%d] instanceof debug.PropertyMirror", i);
4492 CHECK(CompileRun(buffer.start())->BooleanValue());
4495 // Check the property names.
4496 source = "both_values[0].name() == 'a'";
4497 CHECK(CompileRun(source)->BooleanValue());
4499 source = "both_values[1].name() == 'b'";
4500 CHECK(CompileRun(source)->BooleanValue());
4502 source = "both_values[2].name() == 'c'";
4503 CHECK(CompileRun(source)->BooleanValue());
4505 source = "both_values[3].name() == 1";
4506 CHECK(CompileRun(source)->BooleanValue());
4508 source = "both_values[4].name() == 10";
4509 CHECK(CompileRun(source)->BooleanValue());
4513 TEST(HiddenPrototypePropertyMirror) {
4514 // Create a V8 environment with debug access.
4515 DebugLocalContext env;
4516 v8::Isolate* isolate = env->GetIsolate();
4517 v8::HandleScope scope(isolate);
4520 v8::Handle<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
4521 t0->InstanceTemplate()->Set(v8::String::NewFromUtf8(isolate, "x"),
4522 v8::Number::New(isolate, 0));
4523 v8::Handle<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
4524 t1->SetHiddenPrototype(true);
4525 t1->InstanceTemplate()->Set(v8::String::NewFromUtf8(isolate, "y"),
4526 v8::Number::New(isolate, 1));
4527 v8::Handle<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
4528 t2->SetHiddenPrototype(true);
4529 t2->InstanceTemplate()->Set(v8::String::NewFromUtf8(isolate, "z"),
4530 v8::Number::New(isolate, 2));
4531 v8::Handle<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
4532 t3->InstanceTemplate()->Set(v8::String::NewFromUtf8(isolate, "u"),
4533 v8::Number::New(isolate, 3));
4535 // Create object and set them on the global object.
4536 v8::Handle<v8::Object> o0 = t0->GetFunction()->NewInstance();
4537 env->Global()->Set(v8::String::NewFromUtf8(isolate, "o0"), o0);
4538 v8::Handle<v8::Object> o1 = t1->GetFunction()->NewInstance();
4539 env->Global()->Set(v8::String::NewFromUtf8(isolate, "o1"), o1);
4540 v8::Handle<v8::Object> o2 = t2->GetFunction()->NewInstance();
4541 env->Global()->Set(v8::String::NewFromUtf8(isolate, "o2"), o2);
4542 v8::Handle<v8::Object> o3 = t3->GetFunction()->NewInstance();
4543 env->Global()->Set(v8::String::NewFromUtf8(isolate, "o3"), o3);
4545 // Get mirrors for the four objects.
4547 "var o0_mirror = debug.MakeMirror(o0);"
4548 "var o1_mirror = debug.MakeMirror(o1);"
4549 "var o2_mirror = debug.MakeMirror(o2);"
4550 "var o3_mirror = debug.MakeMirror(o3)");
4551 CHECK(CompileRun("o0_mirror instanceof debug.ObjectMirror")->BooleanValue());
4552 CHECK(CompileRun("o1_mirror instanceof debug.ObjectMirror")->BooleanValue());
4553 CHECK(CompileRun("o2_mirror instanceof debug.ObjectMirror")->BooleanValue());
4554 CHECK(CompileRun("o3_mirror instanceof debug.ObjectMirror")->BooleanValue());
4556 // Check that each object has one property.
4557 CHECK_EQ(1, CompileRun(
4558 "o0_mirror.propertyNames().length")->Int32Value());
4559 CHECK_EQ(1, CompileRun(
4560 "o1_mirror.propertyNames().length")->Int32Value());
4561 CHECK_EQ(1, CompileRun(
4562 "o2_mirror.propertyNames().length")->Int32Value());
4563 CHECK_EQ(1, CompileRun(
4564 "o3_mirror.propertyNames().length")->Int32Value());
4566 // Set o1 as prototype for o0. o1 has the hidden prototype flag so all
4567 // properties on o1 should be seen on o0.
4568 o0->Set(v8::String::NewFromUtf8(isolate, "__proto__"), o1);
4569 CHECK_EQ(2, CompileRun(
4570 "o0_mirror.propertyNames().length")->Int32Value());
4571 CHECK_EQ(0, CompileRun(
4572 "o0_mirror.property('x').value().value()")->Int32Value());
4573 CHECK_EQ(1, CompileRun(
4574 "o0_mirror.property('y').value().value()")->Int32Value());
4576 // Set o2 as prototype for o0 (it will end up after o1 as o1 has the hidden
4577 // prototype flag. o2 also has the hidden prototype flag so all properties
4578 // on o2 should be seen on o0 as well as properties on o1.
4579 o0->Set(v8::String::NewFromUtf8(isolate, "__proto__"), o2);
4580 CHECK_EQ(3, CompileRun(
4581 "o0_mirror.propertyNames().length")->Int32Value());
4582 CHECK_EQ(0, CompileRun(
4583 "o0_mirror.property('x').value().value()")->Int32Value());
4584 CHECK_EQ(1, CompileRun(
4585 "o0_mirror.property('y').value().value()")->Int32Value());
4586 CHECK_EQ(2, CompileRun(
4587 "o0_mirror.property('z').value().value()")->Int32Value());
4589 // Set o3 as prototype for o0 (it will end up after o1 and o2 as both o1 and
4590 // o2 has the hidden prototype flag. o3 does not have the hidden prototype
4591 // flag so properties on o3 should not be seen on o0 whereas the properties
4592 // from o1 and o2 should still be seen on o0.
4593 // Final prototype chain: o0 -> o1 -> o2 -> o3
4594 // Hidden prototypes: ^^ ^^
4595 o0->Set(v8::String::NewFromUtf8(isolate, "__proto__"), o3);
4596 CHECK_EQ(3, CompileRun(
4597 "o0_mirror.propertyNames().length")->Int32Value());
4598 CHECK_EQ(1, CompileRun(
4599 "o3_mirror.propertyNames().length")->Int32Value());
4600 CHECK_EQ(0, CompileRun(
4601 "o0_mirror.property('x').value().value()")->Int32Value());
4602 CHECK_EQ(1, CompileRun(
4603 "o0_mirror.property('y').value().value()")->Int32Value());
4604 CHECK_EQ(2, CompileRun(
4605 "o0_mirror.property('z').value().value()")->Int32Value());
4606 CHECK(CompileRun("o0_mirror.property('u').isUndefined()")->BooleanValue());
4608 // The prototype (__proto__) for o0 should be o3 as o1 and o2 are hidden.
4609 CHECK(CompileRun("o0_mirror.protoObject() == o3_mirror")->BooleanValue());
4613 static void ProtperyXNativeGetter(
4614 v8::Local<v8::String> property,
4615 const v8::PropertyCallbackInfo<v8::Value>& info) {
4616 info.GetReturnValue().Set(10);
4620 TEST(NativeGetterPropertyMirror) {
4621 // Create a V8 environment with debug access.
4622 DebugLocalContext env;
4623 v8::Isolate* isolate = env->GetIsolate();
4624 v8::HandleScope scope(isolate);
4627 v8::Handle<v8::String> name = v8::String::NewFromUtf8(isolate, "x");
4628 // Create object with named accessor.
4629 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
4630 named->SetAccessor(name, &ProtperyXNativeGetter, NULL,
4631 v8::Handle<v8::Value>(), v8::DEFAULT, v8::None);
4633 // Create object with named property getter.
4634 env->Global()->Set(v8::String::NewFromUtf8(isolate, "instance"),
4635 named->NewInstance());
4636 CHECK_EQ(10, CompileRun("instance.x")->Int32Value());
4638 // Get mirror for the object with property getter.
4639 CompileRun("var instance_mirror = debug.MakeMirror(instance);");
4641 "instance_mirror instanceof debug.ObjectMirror")->BooleanValue());
4643 CompileRun("var named_names = instance_mirror.propertyNames();");
4644 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
4645 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue());
4647 "instance_mirror.property('x').value().isNumber()")->BooleanValue());
4649 "instance_mirror.property('x').value().value() == 10")->BooleanValue());
4653 static void ProtperyXNativeGetterThrowingError(
4654 v8::Local<v8::String> property,
4655 const v8::PropertyCallbackInfo<v8::Value>& info) {
4656 CompileRun("throw new Error('Error message');");
4660 TEST(NativeGetterThrowingErrorPropertyMirror) {
4661 // Create a V8 environment with debug access.
4662 DebugLocalContext env;
4663 v8::Isolate* isolate = env->GetIsolate();
4664 v8::HandleScope scope(isolate);
4667 v8::Handle<v8::String> name = v8::String::NewFromUtf8(isolate, "x");
4668 // Create object with named accessor.
4669 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
4670 named->SetAccessor(name, &ProtperyXNativeGetterThrowingError, NULL,
4671 v8::Handle<v8::Value>(), v8::DEFAULT, v8::None);
4673 // Create object with named property getter.
4674 env->Global()->Set(v8::String::NewFromUtf8(isolate, "instance"),
4675 named->NewInstance());
4677 // Get mirror for the object with property getter.
4678 CompileRun("var instance_mirror = debug.MakeMirror(instance);");
4680 "instance_mirror instanceof debug.ObjectMirror")->BooleanValue());
4681 CompileRun("named_names = instance_mirror.propertyNames();");
4682 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
4683 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue());
4685 "instance_mirror.property('x').value().isError()")->BooleanValue());
4687 // Check that the message is that passed to the Error constructor.
4689 "instance_mirror.property('x').value().message() == 'Error message'")->
4694 // Test that hidden properties object is not returned as an unnamed property
4695 // among regular properties.
4696 // See http://crbug.com/26491
4697 TEST(NoHiddenProperties) {
4698 // Create a V8 environment with debug access.
4699 DebugLocalContext env;
4700 v8::Isolate* isolate = env->GetIsolate();
4701 v8::HandleScope scope(isolate);
4704 // Create an object in the global scope.
4705 const char* source = "var obj = {a: 1};";
4706 v8::Script::Compile(v8::String::NewFromUtf8(isolate, source))
4708 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
4709 env->Global()->Get(v8::String::NewFromUtf8(isolate, "obj")));
4710 // Set a hidden property on the object.
4711 obj->SetHiddenValue(
4712 v8::String::NewFromUtf8(isolate, "v8::test-debug::a"),
4713 v8::Int32::New(isolate, 11));
4715 // Get mirror for the object with property getter.
4716 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
4718 "obj_mirror instanceof debug.ObjectMirror")->BooleanValue());
4719 CompileRun("var named_names = obj_mirror.propertyNames();");
4720 // There should be exactly one property. But there is also an unnamed
4721 // property whose value is hidden properties dictionary. The latter
4722 // property should not be in the list of reguar properties.
4723 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
4724 CHECK(CompileRun("named_names[0] == 'a'")->BooleanValue());
4726 "obj_mirror.property('a').value().value() == 1")->BooleanValue());
4728 // Object created by t0 will become hidden prototype of object 'obj'.
4729 v8::Handle<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
4730 t0->InstanceTemplate()->Set(v8::String::NewFromUtf8(isolate, "b"),
4731 v8::Number::New(isolate, 2));
4732 t0->SetHiddenPrototype(true);
4733 v8::Handle<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
4734 t1->InstanceTemplate()->Set(v8::String::NewFromUtf8(isolate, "c"),
4735 v8::Number::New(isolate, 3));
4737 // Create proto objects, add hidden properties to them and set them on
4738 // the global object.
4739 v8::Handle<v8::Object> protoObj = t0->GetFunction()->NewInstance();
4740 protoObj->SetHiddenValue(
4741 v8::String::NewFromUtf8(isolate, "v8::test-debug::b"),
4742 v8::Int32::New(isolate, 12));
4743 env->Global()->Set(v8::String::NewFromUtf8(isolate, "protoObj"),
4745 v8::Handle<v8::Object> grandProtoObj = t1->GetFunction()->NewInstance();
4746 grandProtoObj->SetHiddenValue(
4747 v8::String::NewFromUtf8(isolate, "v8::test-debug::c"),
4748 v8::Int32::New(isolate, 13));
4750 v8::String::NewFromUtf8(isolate, "grandProtoObj"),
4753 // Setting prototypes: obj->protoObj->grandProtoObj
4754 protoObj->Set(v8::String::NewFromUtf8(isolate, "__proto__"),
4756 obj->Set(v8::String::NewFromUtf8(isolate, "__proto__"), protoObj);
4758 // Get mirror for the object with property getter.
4759 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
4761 "obj_mirror instanceof debug.ObjectMirror")->BooleanValue());
4762 CompileRun("var named_names = obj_mirror.propertyNames();");
4763 // There should be exactly two properties - one from the object itself and
4764 // another from its hidden prototype.
4765 CHECK_EQ(2, CompileRun("named_names.length")->Int32Value());
4766 CHECK(CompileRun("named_names.sort(); named_names[0] == 'a' &&"
4767 "named_names[1] == 'b'")->BooleanValue());
4769 "obj_mirror.property('a').value().value() == 1")->BooleanValue());
4771 "obj_mirror.property('b').value().value() == 2")->BooleanValue());
4775 // Multithreaded tests of JSON debugger protocol
4779 // Provides synchronization between N threads, where N is a template parameter.
4780 // The Wait() call blocks a thread until it is called for the Nth time, then all
4781 // calls return. Each ThreadBarrier object can only be used once.
4783 class ThreadBarrier FINAL {
4785 ThreadBarrier() : num_blocked_(0) {}
4788 LockGuard<Mutex> lock_guard(&mutex_);
4789 if (num_blocked_ != 0) {
4790 CHECK_EQ(N, num_blocked_);
4795 LockGuard<Mutex> lock_guard(&mutex_);
4796 CHECK_LT(num_blocked_, N);
4798 if (N == num_blocked_) {
4799 // Signal and unblock all waiting threads.
4801 printf("BARRIER\n\n");
4803 } else { // Wait for the semaphore.
4804 while (num_blocked_ < N) {
4808 CHECK_EQ(N, num_blocked_);
4812 ConditionVariable cv_;
4816 STATIC_ASSERT(N > 0);
4818 DISALLOW_COPY_AND_ASSIGN(ThreadBarrier);
4822 // A set containing enough barriers and semaphores for any of the tests.
4825 Barriers() : semaphore_1(0), semaphore_2(0) {}
4826 ThreadBarrier<2> barrier_1;
4827 ThreadBarrier<2> barrier_2;
4828 ThreadBarrier<2> barrier_3;
4829 ThreadBarrier<2> barrier_4;
4830 ThreadBarrier<2> barrier_5;
4831 v8::base::Semaphore semaphore_1;
4832 v8::base::Semaphore semaphore_2;
4836 // We match parts of the message to decide if it is a break message.
4837 bool IsBreakEventMessage(char *message) {
4838 const char* type_event = "\"type\":\"event\"";
4839 const char* event_break = "\"event\":\"break\"";
4840 // Does the message contain both type:event and event:break?
4841 return strstr(message, type_event) != NULL &&
4842 strstr(message, event_break) != NULL;
4846 // We match parts of the message to decide if it is a exception message.
4847 bool IsExceptionEventMessage(char *message) {
4848 const char* type_event = "\"type\":\"event\"";
4849 const char* event_exception = "\"event\":\"exception\"";
4850 // Does the message contain both type:event and event:exception?
4851 return strstr(message, type_event) != NULL &&
4852 strstr(message, event_exception) != NULL;
4856 // We match the message wether it is an evaluate response message.
4857 bool IsEvaluateResponseMessage(char* message) {
4858 const char* type_response = "\"type\":\"response\"";
4859 const char* command_evaluate = "\"command\":\"evaluate\"";
4860 // Does the message contain both type:response and command:evaluate?
4861 return strstr(message, type_response) != NULL &&
4862 strstr(message, command_evaluate) != NULL;
4866 static int StringToInt(const char* s) {
4867 return atoi(s); // NOLINT
4871 // We match parts of the message to get evaluate result int value.
4872 int GetEvaluateIntResult(char *message) {
4873 const char* value = "\"value\":";
4874 char* pos = strstr(message, value);
4879 res = StringToInt(pos + strlen(value));
4884 // We match parts of the message to get hit breakpoint id.
4885 int GetBreakpointIdFromBreakEventMessage(char *message) {
4886 const char* breakpoints = "\"breakpoints\":[";
4887 char* pos = strstr(message, breakpoints);
4892 res = StringToInt(pos + strlen(breakpoints));
4897 // We match parts of the message to get total frames number.
4898 int GetTotalFramesInt(char *message) {
4899 const char* prefix = "\"totalFrames\":";
4900 char* pos = strstr(message, prefix);
4904 pos += strlen(prefix);
4905 int res = StringToInt(pos);
4910 // We match parts of the message to get source line.
4911 int GetSourceLineFromBreakEventMessage(char *message) {
4912 const char* source_line = "\"sourceLine\":";
4913 char* pos = strstr(message, source_line);
4918 res = StringToInt(pos + strlen(source_line));
4923 /* Test MessageQueues */
4924 /* Tests the message queues that hold debugger commands and
4925 * response messages to the debugger. Fills queues and makes
4928 Barriers message_queue_barriers;
4930 // This is the debugger thread, that executes no v8 calls except
4931 // placing JSON debugger commands in the queue.
4932 class MessageQueueDebuggerThread : public v8::base::Thread {
4934 MessageQueueDebuggerThread()
4935 : Thread(Options("MessageQueueDebuggerThread")) {}
4940 static void MessageHandler(const v8::Debug::Message& message) {
4941 v8::Handle<v8::String> json = message.GetJSON();
4942 v8::String::Utf8Value utf8(json);
4943 if (IsBreakEventMessage(*utf8)) {
4944 // Lets test script wait until break occurs to send commands.
4945 // Signals when a break is reported.
4946 message_queue_barriers.semaphore_2.Signal();
4949 // Allow message handler to block on a semaphore, to test queueing of
4950 // messages while blocked.
4951 message_queue_barriers.semaphore_1.Wait();
4955 void MessageQueueDebuggerThread::Run() {
4956 const int kBufferSize = 1000;
4957 uint16_t buffer_1[kBufferSize];
4958 uint16_t buffer_2[kBufferSize];
4959 const char* command_1 =
4961 "\"type\":\"request\","
4962 "\"command\":\"evaluate\","
4963 "\"arguments\":{\"expression\":\"1+2\"}}";
4964 const char* command_2 =
4966 "\"type\":\"request\","
4967 "\"command\":\"evaluate\","
4968 "\"arguments\":{\"expression\":\"1+a\"}}";
4969 const char* command_3 =
4971 "\"type\":\"request\","
4972 "\"command\":\"evaluate\","
4973 "\"arguments\":{\"expression\":\"c.d * b\"}}";
4974 const char* command_continue =
4976 "\"type\":\"request\","
4977 "\"command\":\"continue\"}";
4978 const char* command_single_step =
4980 "\"type\":\"request\","
4981 "\"command\":\"continue\","
4982 "\"arguments\":{\"stepaction\":\"next\"}}";
4984 /* Interleaved sequence of actions by the two threads:*/
4985 // Main thread compiles and runs source_1
4986 message_queue_barriers.semaphore_1.Signal();
4987 message_queue_barriers.barrier_1.Wait();
4988 // Post 6 commands, filling the command queue and making it expand.
4989 // These calls return immediately, but the commands stay on the queue
4990 // until the execution of source_2.
4991 // Note: AsciiToUtf16 executes before SendCommand, so command is copied
4992 // to buffer before buffer is sent to SendCommand.
4993 v8::Isolate* isolate = CcTest::isolate();
4994 v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_1, buffer_1));
4995 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_2, buffer_2));
4996 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
4997 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
4998 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
4999 message_queue_barriers.barrier_2.Wait();
5000 // Main thread compiles and runs source_2.
5001 // Queued commands are executed at the start of compilation of source_2(
5002 // beforeCompile event).
5003 // Free the message handler to process all the messages from the queue. 7
5004 // messages are expected: 2 afterCompile events and 5 responses.
5005 // All the commands added so far will fail to execute as long as call stack
5006 // is empty on beforeCompile event.
5007 for (int i = 0; i < 6 ; ++i) {
5008 message_queue_barriers.semaphore_1.Signal();
5010 message_queue_barriers.barrier_3.Wait();
5011 // Main thread compiles and runs source_3.
5012 // Don't stop in the afterCompile handler.
5013 message_queue_barriers.semaphore_1.Signal();
5014 // source_3 includes a debugger statement, which causes a break event.
5015 // Wait on break event from hitting "debugger" statement
5016 message_queue_barriers.semaphore_2.Wait();
5017 // These should execute after the "debugger" statement in source_2
5018 v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_1, buffer_1));
5019 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_2, buffer_2));
5020 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
5021 v8::Debug::SendCommand(
5022 isolate, buffer_2, AsciiToUtf16(command_single_step, buffer_2));
5023 // Run after 2 break events, 4 responses.
5024 for (int i = 0; i < 6 ; ++i) {
5025 message_queue_barriers.semaphore_1.Signal();
5027 // Wait on break event after a single step executes.
5028 message_queue_barriers.semaphore_2.Wait();
5029 v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_2, buffer_1));
5030 v8::Debug::SendCommand(
5031 isolate, buffer_2, AsciiToUtf16(command_continue, buffer_2));
5032 // Run after 2 responses.
5033 for (int i = 0; i < 2 ; ++i) {
5034 message_queue_barriers.semaphore_1.Signal();
5036 // Main thread continues running source_3 to end, waits for this thread.
5040 // This thread runs the v8 engine.
5041 TEST(MessageQueues) {
5042 MessageQueueDebuggerThread message_queue_debugger_thread;
5044 // Create a V8 environment
5045 DebugLocalContext env;
5046 v8::HandleScope scope(env->GetIsolate());
5047 v8::Debug::SetMessageHandler(MessageHandler);
5048 message_queue_debugger_thread.Start();
5050 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
5051 const char* source_2 = "e = 17;";
5052 const char* source_3 = "a = 4; debugger; a = 5; a = 6; a = 7;";
5054 // See MessageQueueDebuggerThread::Run for interleaved sequence of
5055 // API calls and events in the two threads.
5056 CompileRun(source_1);
5057 message_queue_barriers.barrier_1.Wait();
5058 message_queue_barriers.barrier_2.Wait();
5059 CompileRun(source_2);
5060 message_queue_barriers.barrier_3.Wait();
5061 CompileRun(source_3);
5062 message_queue_debugger_thread.Join();
5067 class TestClientData : public v8::Debug::ClientData {
5070 constructor_call_counter++;
5072 virtual ~TestClientData() {
5073 destructor_call_counter++;
5076 static void ResetCounters() {
5077 constructor_call_counter = 0;
5078 destructor_call_counter = 0;
5081 static int constructor_call_counter;
5082 static int destructor_call_counter;
5085 int TestClientData::constructor_call_counter = 0;
5086 int TestClientData::destructor_call_counter = 0;
5089 // Tests that MessageQueue doesn't destroy client data when expands and
5090 // does destroy when it dies.
5091 TEST(MessageQueueExpandAndDestroy) {
5092 TestClientData::ResetCounters();
5093 { // Create a scope for the queue.
5094 CommandMessageQueue queue(1);
5095 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5096 new TestClientData()));
5097 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5098 new TestClientData()));
5099 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5100 new TestClientData()));
5101 CHECK_EQ(0, TestClientData::destructor_call_counter);
5102 queue.Get().Dispose();
5103 CHECK_EQ(1, TestClientData::destructor_call_counter);
5104 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5105 new TestClientData()));
5106 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5107 new TestClientData()));
5108 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5109 new TestClientData()));
5110 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5111 new TestClientData()));
5112 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5113 new TestClientData()));
5114 CHECK_EQ(1, TestClientData::destructor_call_counter);
5115 queue.Get().Dispose();
5116 CHECK_EQ(2, TestClientData::destructor_call_counter);
5118 // All the client data should be destroyed when the queue is destroyed.
5119 CHECK_EQ(TestClientData::destructor_call_counter,
5120 TestClientData::destructor_call_counter);
5124 static int handled_client_data_instances_count = 0;
5125 static void MessageHandlerCountingClientData(
5126 const v8::Debug::Message& message) {
5127 if (message.GetClientData() != NULL) {
5128 handled_client_data_instances_count++;
5133 // Tests that all client data passed to the debugger are sent to the handler.
5134 TEST(SendClientDataToHandler) {
5135 // Create a V8 environment
5136 DebugLocalContext env;
5137 v8::Isolate* isolate = env->GetIsolate();
5138 v8::HandleScope scope(isolate);
5139 TestClientData::ResetCounters();
5140 handled_client_data_instances_count = 0;
5141 v8::Debug::SetMessageHandler(MessageHandlerCountingClientData);
5142 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
5143 const int kBufferSize = 1000;
5144 uint16_t buffer[kBufferSize];
5145 const char* command_1 =
5147 "\"type\":\"request\","
5148 "\"command\":\"evaluate\","
5149 "\"arguments\":{\"expression\":\"1+2\"}}";
5150 const char* command_2 =
5152 "\"type\":\"request\","
5153 "\"command\":\"evaluate\","
5154 "\"arguments\":{\"expression\":\"1+a\"}}";
5155 const char* command_continue =
5157 "\"type\":\"request\","
5158 "\"command\":\"continue\"}";
5160 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_1, buffer),
5161 new TestClientData());
5162 v8::Debug::SendCommand(
5163 isolate, buffer, AsciiToUtf16(command_2, buffer), NULL);
5164 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_2, buffer),
5165 new TestClientData());
5166 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_2, buffer),
5167 new TestClientData());
5168 // All the messages will be processed on beforeCompile event.
5169 CompileRun(source_1);
5170 v8::Debug::SendCommand(
5171 isolate, buffer, AsciiToUtf16(command_continue, buffer));
5172 CHECK_EQ(3, TestClientData::constructor_call_counter);
5173 CHECK_EQ(TestClientData::constructor_call_counter,
5174 handled_client_data_instances_count);
5175 CHECK_EQ(TestClientData::constructor_call_counter,
5176 TestClientData::destructor_call_counter);
5180 /* Test ThreadedDebugging */
5181 /* This test interrupts a running infinite loop that is
5182 * occupying the v8 thread by a break command from the
5183 * debugger thread. It then changes the value of a
5184 * global object, to make the loop terminate.
5187 Barriers threaded_debugging_barriers;
5189 class V8Thread : public v8::base::Thread {
5191 V8Thread() : Thread(Options("V8Thread")) {}
5193 v8::Isolate* isolate() { return isolate_; }
5196 v8::Isolate* isolate_;
5199 class DebuggerThread : public v8::base::Thread {
5201 explicit DebuggerThread(v8::Isolate* isolate)
5202 : Thread(Options("DebuggerThread")), isolate_(isolate) {}
5206 v8::Isolate* isolate_;
5210 static void ThreadedAtBarrier1(
5211 const v8::FunctionCallbackInfo<v8::Value>& args) {
5212 threaded_debugging_barriers.barrier_1.Wait();
5216 static void ThreadedMessageHandler(const v8::Debug::Message& message) {
5217 static char print_buffer[1000];
5218 v8::String::Value json(message.GetJSON());
5219 Utf16ToAscii(*json, json.length(), print_buffer);
5220 if (IsBreakEventMessage(print_buffer)) {
5221 // Check that we are inside the while loop.
5222 int source_line = GetSourceLineFromBreakEventMessage(print_buffer);
5223 CHECK(8 <= source_line && source_line <= 13);
5224 threaded_debugging_barriers.barrier_2.Wait();
5229 void V8Thread::Run() {
5230 const char* source =
5232 "function bar( new_value ) {\n"
5233 " flag = new_value;\n"
5234 " return \"Return from bar(\" + new_value + \")\";\n"
5237 "function foo() {\n"
5239 " while ( flag == true ) {\n"
5240 " if ( x == 1 ) {\n"
5241 " ThreadedAtBarrier1();\n"
5249 isolate_ = v8::Isolate::New();
5250 threaded_debugging_barriers.barrier_3.Wait();
5252 v8::Isolate::Scope isolate_scope(isolate_);
5253 DebugLocalContext env(isolate_);
5254 v8::HandleScope scope(isolate_);
5255 v8::Debug::SetMessageHandler(&ThreadedMessageHandler);
5256 v8::Handle<v8::ObjectTemplate> global_template =
5257 v8::ObjectTemplate::New(env->GetIsolate());
5258 global_template->Set(
5259 v8::String::NewFromUtf8(env->GetIsolate(), "ThreadedAtBarrier1"),
5260 v8::FunctionTemplate::New(isolate_, ThreadedAtBarrier1));
5261 v8::Handle<v8::Context> context =
5262 v8::Context::New(isolate_, NULL, global_template);
5263 v8::Context::Scope context_scope(context);
5267 isolate_->Dispose();
5271 void DebuggerThread::Run() {
5272 const int kBufSize = 1000;
5273 uint16_t buffer[kBufSize];
5275 const char* command_1 = "{\"seq\":102,"
5276 "\"type\":\"request\","
5277 "\"command\":\"evaluate\","
5278 "\"arguments\":{\"expression\":\"bar(false)\"}}";
5279 const char* command_2 = "{\"seq\":103,"
5280 "\"type\":\"request\","
5281 "\"command\":\"continue\"}";
5283 threaded_debugging_barriers.barrier_1.Wait();
5284 v8::Debug::DebugBreak(isolate_);
5285 threaded_debugging_barriers.barrier_2.Wait();
5286 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_1, buffer));
5287 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_2, buffer));
5291 TEST(ThreadedDebugging) {
5294 // Create a V8 environment
5296 threaded_debugging_barriers.barrier_3.Wait();
5297 DebuggerThread debugger_thread(v8_thread.isolate());
5298 debugger_thread.Start();
5301 debugger_thread.Join();
5305 /* Test RecursiveBreakpoints */
5306 /* In this test, the debugger evaluates a function with a breakpoint, after
5307 * hitting a breakpoint in another function. We do this with both values
5308 * of the flag enabling recursive breakpoints, and verify that the second
5309 * breakpoint is hit when enabled, and missed when disabled.
5312 class BreakpointsV8Thread : public v8::base::Thread {
5314 BreakpointsV8Thread() : Thread(Options("BreakpointsV8Thread")) {}
5317 v8::Isolate* isolate() { return isolate_; }
5320 v8::Isolate* isolate_;
5323 class BreakpointsDebuggerThread : public v8::base::Thread {
5325 BreakpointsDebuggerThread(bool global_evaluate, v8::Isolate* isolate)
5326 : Thread(Options("BreakpointsDebuggerThread")),
5327 global_evaluate_(global_evaluate),
5328 isolate_(isolate) {}
5332 bool global_evaluate_;
5333 v8::Isolate* isolate_;
5337 Barriers* breakpoints_barriers;
5338 int break_event_breakpoint_id;
5339 int evaluate_int_result;
5341 static void BreakpointsMessageHandler(const v8::Debug::Message& message) {
5342 static char print_buffer[1000];
5343 v8::String::Value json(message.GetJSON());
5344 Utf16ToAscii(*json, json.length(), print_buffer);
5346 if (IsBreakEventMessage(print_buffer)) {
5347 break_event_breakpoint_id =
5348 GetBreakpointIdFromBreakEventMessage(print_buffer);
5349 breakpoints_barriers->semaphore_1.Signal();
5350 } else if (IsEvaluateResponseMessage(print_buffer)) {
5351 evaluate_int_result = GetEvaluateIntResult(print_buffer);
5352 breakpoints_barriers->semaphore_1.Signal();
5357 void BreakpointsV8Thread::Run() {
5358 const char* source_1 = "var y_global = 3;\n"
5359 "function cat( new_value ) {\n"
5360 " var x = new_value;\n"
5361 " y_global = y_global + 4;\n"
5363 " y_global = y_global + 5;\n"
5367 "function dog() {\n"
5375 const char* source_2 = "cat(17);\n"
5378 isolate_ = v8::Isolate::New();
5379 breakpoints_barriers->barrier_3.Wait();
5381 v8::Isolate::Scope isolate_scope(isolate_);
5382 DebugLocalContext env(isolate_);
5383 v8::HandleScope scope(isolate_);
5384 v8::Debug::SetMessageHandler(&BreakpointsMessageHandler);
5386 CompileRun(source_1);
5387 breakpoints_barriers->barrier_1.Wait();
5388 breakpoints_barriers->barrier_2.Wait();
5389 CompileRun(source_2);
5391 isolate_->Dispose();
5395 void BreakpointsDebuggerThread::Run() {
5396 const int kBufSize = 1000;
5397 uint16_t buffer[kBufSize];
5399 const char* command_1 = "{\"seq\":101,"
5400 "\"type\":\"request\","
5401 "\"command\":\"setbreakpoint\","
5402 "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}";
5403 const char* command_2 = "{\"seq\":102,"
5404 "\"type\":\"request\","
5405 "\"command\":\"setbreakpoint\","
5406 "\"arguments\":{\"type\":\"function\",\"target\":\"dog\",\"line\":3}}";
5407 const char* command_3;
5408 if (this->global_evaluate_) {
5409 command_3 = "{\"seq\":103,"
5410 "\"type\":\"request\","
5411 "\"command\":\"evaluate\","
5412 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false,"
5413 "\"global\":true}}";
5415 command_3 = "{\"seq\":103,"
5416 "\"type\":\"request\","
5417 "\"command\":\"evaluate\","
5418 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false}}";
5420 const char* command_4;
5421 if (this->global_evaluate_) {
5422 command_4 = "{\"seq\":104,"
5423 "\"type\":\"request\","
5424 "\"command\":\"evaluate\","
5425 "\"arguments\":{\"expression\":\"100 + 8\",\"disable_break\":true,"
5426 "\"global\":true}}";
5428 command_4 = "{\"seq\":104,"
5429 "\"type\":\"request\","
5430 "\"command\":\"evaluate\","
5431 "\"arguments\":{\"expression\":\"x + 1\",\"disable_break\":true}}";
5433 const char* command_5 = "{\"seq\":105,"
5434 "\"type\":\"request\","
5435 "\"command\":\"continue\"}";
5436 const char* command_6 = "{\"seq\":106,"
5437 "\"type\":\"request\","
5438 "\"command\":\"continue\"}";
5439 const char* command_7;
5440 if (this->global_evaluate_) {
5441 command_7 = "{\"seq\":107,"
5442 "\"type\":\"request\","
5443 "\"command\":\"evaluate\","
5444 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true,"
5445 "\"global\":true}}";
5447 command_7 = "{\"seq\":107,"
5448 "\"type\":\"request\","
5449 "\"command\":\"evaluate\","
5450 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true}}";
5452 const char* command_8 = "{\"seq\":108,"
5453 "\"type\":\"request\","
5454 "\"command\":\"continue\"}";
5457 // v8 thread initializes, runs source_1
5458 breakpoints_barriers->barrier_1.Wait();
5459 // 1:Set breakpoint in cat() (will get id 1).
5460 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_1, buffer));
5461 // 2:Set breakpoint in dog() (will get id 2).
5462 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_2, buffer));
5463 breakpoints_barriers->barrier_2.Wait();
5464 // V8 thread starts compiling source_2.
5465 // Automatic break happens, to run queued commands
5466 // breakpoints_barriers->semaphore_1.Wait();
5467 // Commands 1 through 3 run, thread continues.
5468 // v8 thread runs source_2 to breakpoint in cat().
5469 // message callback receives break event.
5470 breakpoints_barriers->semaphore_1.Wait();
5471 // Must have hit breakpoint #1.
5472 CHECK_EQ(1, break_event_breakpoint_id);
5473 // 4:Evaluate dog() (which has a breakpoint).
5474 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_3, buffer));
5475 // V8 thread hits breakpoint in dog().
5476 breakpoints_barriers->semaphore_1.Wait(); // wait for break event
5477 // Must have hit breakpoint #2.
5478 CHECK_EQ(2, break_event_breakpoint_id);
5479 // 5:Evaluate (x + 1).
5480 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_4, buffer));
5481 // Evaluate (x + 1) finishes.
5482 breakpoints_barriers->semaphore_1.Wait();
5483 // Must have result 108.
5484 CHECK_EQ(108, evaluate_int_result);
5485 // 6:Continue evaluation of dog().
5486 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_5, buffer));
5487 // Evaluate dog() finishes.
5488 breakpoints_barriers->semaphore_1.Wait();
5489 // Must have result 107.
5490 CHECK_EQ(107, evaluate_int_result);
5491 // 7:Continue evaluation of source_2, finish cat(17), hit breakpoint
5493 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_6, buffer));
5494 // Message callback gets break event.
5495 breakpoints_barriers->semaphore_1.Wait(); // wait for break event
5496 // Must have hit breakpoint #1.
5497 CHECK_EQ(1, break_event_breakpoint_id);
5498 // 8: Evaluate dog() with breaks disabled.
5499 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_7, buffer));
5500 // Evaluate dog() finishes.
5501 breakpoints_barriers->semaphore_1.Wait();
5502 // Must have result 116.
5503 CHECK_EQ(116, evaluate_int_result);
5504 // 9: Continue evaluation of source2, reach end.
5505 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_8, buffer));
5509 void TestRecursiveBreakpointsGeneric(bool global_evaluate) {
5510 BreakpointsV8Thread breakpoints_v8_thread;
5512 // Create a V8 environment
5513 Barriers stack_allocated_breakpoints_barriers;
5514 breakpoints_barriers = &stack_allocated_breakpoints_barriers;
5516 breakpoints_v8_thread.Start();
5517 breakpoints_barriers->barrier_3.Wait();
5518 BreakpointsDebuggerThread breakpoints_debugger_thread(
5519 global_evaluate, breakpoints_v8_thread.isolate());
5520 breakpoints_debugger_thread.Start();
5522 breakpoints_v8_thread.Join();
5523 breakpoints_debugger_thread.Join();
5527 TEST(RecursiveBreakpoints) {
5528 TestRecursiveBreakpointsGeneric(false);
5532 TEST(RecursiveBreakpointsGlobal) {
5533 TestRecursiveBreakpointsGeneric(true);
5537 static void DummyDebugEventListener(
5538 const v8::Debug::EventDetails& event_details) {
5542 TEST(SetDebugEventListenerOnUninitializedVM) {
5543 v8::Debug::SetDebugEventListener(DummyDebugEventListener);
5547 static void DummyMessageHandler(const v8::Debug::Message& message) {
5551 TEST(SetMessageHandlerOnUninitializedVM) {
5552 v8::Debug::SetMessageHandler(DummyMessageHandler);
5556 // Source for a JavaScript function which returns the data parameter of a
5557 // function called in the context of the debugger. If no data parameter is
5558 // passed it throws an exception.
5559 static const char* debugger_call_with_data_source =
5560 "function debugger_call_with_data(exec_state, data) {"
5561 " if (data) return data;"
5564 v8::Handle<v8::Function> debugger_call_with_data;
5567 // Source for a JavaScript function which returns the data parameter of a
5568 // function called in the context of the debugger. If no data parameter is
5569 // passed it throws an exception.
5570 static const char* debugger_call_with_closure_source =
5572 "(function (exec_state) {"
5573 " if (exec_state.y) return x - 1;"
5574 " exec_state.y = x;"
5575 " return exec_state.y"
5577 v8::Handle<v8::Function> debugger_call_with_closure;
5579 // Function to retrieve the number of JavaScript frames by calling a JavaScript
5581 static void CheckFrameCount(const v8::FunctionCallbackInfo<v8::Value>& args) {
5582 CHECK(v8::Debug::Call(frame_count)->IsNumber());
5583 CHECK_EQ(args[0]->Int32Value(),
5584 v8::Debug::Call(frame_count)->Int32Value());
5588 // Function to retrieve the source line of the top JavaScript frame by calling a
5589 // JavaScript function in the debugger.
5590 static void CheckSourceLine(const v8::FunctionCallbackInfo<v8::Value>& args) {
5591 CHECK(v8::Debug::Call(frame_source_line)->IsNumber());
5592 CHECK_EQ(args[0]->Int32Value(),
5593 v8::Debug::Call(frame_source_line)->Int32Value());
5597 // Function to test passing an additional parameter to a JavaScript function
5598 // called in the debugger. It also tests that functions called in the debugger
5599 // can throw exceptions.
5600 static void CheckDataParameter(
5601 const v8::FunctionCallbackInfo<v8::Value>& args) {
5602 v8::Handle<v8::String> data =
5603 v8::String::NewFromUtf8(args.GetIsolate(), "Test");
5604 CHECK(v8::Debug::Call(debugger_call_with_data, data)->IsString());
5606 for (int i = 0; i < 3; i++) {
5607 v8::TryCatch catcher;
5608 CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
5609 CHECK(catcher.HasCaught());
5610 CHECK(catcher.Exception()->IsString());
5615 // Function to test using a JavaScript with closure in the debugger.
5616 static void CheckClosure(const v8::FunctionCallbackInfo<v8::Value>& args) {
5617 CHECK(v8::Debug::Call(debugger_call_with_closure)->IsNumber());
5618 CHECK_EQ(3, v8::Debug::Call(debugger_call_with_closure)->Int32Value());
5622 // Test functions called through the debugger.
5623 TEST(CallFunctionInDebugger) {
5624 // Create and enter a context with the functions CheckFrameCount,
5625 // CheckSourceLine and CheckDataParameter installed.
5626 v8::Isolate* isolate = CcTest::isolate();
5627 v8::HandleScope scope(isolate);
5628 v8::Handle<v8::ObjectTemplate> global_template =
5629 v8::ObjectTemplate::New(isolate);
5630 global_template->Set(
5631 v8::String::NewFromUtf8(isolate, "CheckFrameCount"),
5632 v8::FunctionTemplate::New(isolate, CheckFrameCount));
5633 global_template->Set(
5634 v8::String::NewFromUtf8(isolate, "CheckSourceLine"),
5635 v8::FunctionTemplate::New(isolate, CheckSourceLine));
5636 global_template->Set(
5637 v8::String::NewFromUtf8(isolate, "CheckDataParameter"),
5638 v8::FunctionTemplate::New(isolate, CheckDataParameter));
5639 global_template->Set(
5640 v8::String::NewFromUtf8(isolate, "CheckClosure"),
5641 v8::FunctionTemplate::New(isolate, CheckClosure));
5642 v8::Handle<v8::Context> context = v8::Context::New(isolate,
5645 v8::Context::Scope context_scope(context);
5647 // Compile a function for checking the number of JavaScript frames.
5648 v8::Script::Compile(
5649 v8::String::NewFromUtf8(isolate, frame_count_source))->Run();
5650 frame_count = v8::Local<v8::Function>::Cast(context->Global()->Get(
5651 v8::String::NewFromUtf8(isolate, "frame_count")));
5653 // Compile a function for returning the source line for the top frame.
5654 v8::Script::Compile(v8::String::NewFromUtf8(isolate,
5655 frame_source_line_source))->Run();
5656 frame_source_line = v8::Local<v8::Function>::Cast(context->Global()->Get(
5657 v8::String::NewFromUtf8(isolate, "frame_source_line")));
5659 // Compile a function returning the data parameter.
5660 v8::Script::Compile(v8::String::NewFromUtf8(isolate,
5661 debugger_call_with_data_source))
5663 debugger_call_with_data = v8::Local<v8::Function>::Cast(
5664 context->Global()->Get(v8::String::NewFromUtf8(
5665 isolate, "debugger_call_with_data")));
5667 // Compile a function capturing closure.
5668 debugger_call_with_closure =
5669 v8::Local<v8::Function>::Cast(v8::Script::Compile(
5670 v8::String::NewFromUtf8(isolate,
5671 debugger_call_with_closure_source))->Run());
5673 // Calling a function through the debugger returns 0 frames if there are
5674 // no JavaScript frames.
5675 CHECK_EQ(v8::Integer::New(isolate, 0),
5676 v8::Debug::Call(frame_count));
5678 // Test that the number of frames can be retrieved.
5679 v8::Script::Compile(
5680 v8::String::NewFromUtf8(isolate, "CheckFrameCount(1)"))->Run();
5681 v8::Script::Compile(v8::String::NewFromUtf8(isolate,
5683 " CheckFrameCount(2);"
5686 // Test that the source line can be retrieved.
5687 v8::Script::Compile(
5688 v8::String::NewFromUtf8(isolate, "CheckSourceLine(0)"))->Run();
5689 v8::Script::Compile(v8::String::NewFromUtf8(isolate,
5691 " CheckSourceLine(1)\n"
5692 " CheckSourceLine(2)\n"
5693 " CheckSourceLine(3)\n"
5696 // Test that a parameter can be passed to a function called in the debugger.
5697 v8::Script::Compile(v8::String::NewFromUtf8(isolate,
5698 "CheckDataParameter()"))->Run();
5700 // Test that a function with closure can be run in the debugger.
5701 v8::Script::Compile(
5702 v8::String::NewFromUtf8(isolate, "CheckClosure()"))->Run();
5704 // Test that the source line is correct when there is a line offset.
5705 v8::ScriptOrigin origin(v8::String::NewFromUtf8(isolate, "test"),
5706 v8::Integer::New(isolate, 7));
5707 v8::Script::Compile(
5708 v8::String::NewFromUtf8(isolate, "CheckSourceLine(7)"), &origin)
5710 v8::Script::Compile(v8::String::NewFromUtf8(isolate,
5712 " CheckSourceLine(8)\n"
5713 " CheckSourceLine(9)\n"
5714 " CheckSourceLine(10)\n"
5720 // Debugger message handler which counts the number of breaks.
5721 static void SendContinueCommand();
5722 static void MessageHandlerBreakPointHitCount(
5723 const v8::Debug::Message& message) {
5724 if (message.IsEvent() && message.GetEvent() == v8::Break) {
5725 // Count the number of breaks.
5726 break_point_hit_count++;
5728 SendContinueCommand();
5733 // Test that clearing the debug event listener actually clears all break points
5734 // and related information.
5735 TEST(DebuggerUnload) {
5736 DebugLocalContext env;
5738 // Check debugger is unloaded before it is used.
5739 CheckDebuggerUnloaded();
5741 // Set a debug event listener.
5742 break_point_hit_count = 0;
5743 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
5745 v8::HandleScope scope(env->GetIsolate());
5746 // Create a couple of functions for the test.
5747 v8::Local<v8::Function> foo =
5748 CompileFunction(&env, "function foo(){x=1}", "foo");
5749 v8::Local<v8::Function> bar =
5750 CompileFunction(&env, "function bar(){y=2}", "bar");
5752 // Set some break points.
5753 SetBreakPoint(foo, 0);
5754 SetBreakPoint(foo, 4);
5755 SetBreakPoint(bar, 0);
5756 SetBreakPoint(bar, 4);
5758 // Make sure that the break points are there.
5759 break_point_hit_count = 0;
5760 foo->Call(env->Global(), 0, NULL);
5761 CHECK_EQ(2, break_point_hit_count);
5762 bar->Call(env->Global(), 0, NULL);
5763 CHECK_EQ(4, break_point_hit_count);
5766 // Remove the debug event listener without clearing breakpoints. Do this
5767 // outside a handle scope.
5768 v8::Debug::SetDebugEventListener(NULL);
5769 CheckDebuggerUnloaded(true);
5771 // Now set a debug message handler.
5772 break_point_hit_count = 0;
5773 v8::Debug::SetMessageHandler(MessageHandlerBreakPointHitCount);
5775 v8::HandleScope scope(env->GetIsolate());
5777 // Get the test functions again.
5778 v8::Local<v8::Function> foo(v8::Local<v8::Function>::Cast(
5779 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo"))));
5781 foo->Call(env->Global(), 0, NULL);
5782 CHECK_EQ(0, break_point_hit_count);
5784 // Set break points and run again.
5785 SetBreakPoint(foo, 0);
5786 SetBreakPoint(foo, 4);
5787 foo->Call(env->Global(), 0, NULL);
5788 CHECK_EQ(2, break_point_hit_count);
5791 // Remove the debug message handler without clearing breakpoints. Do this
5792 // outside a handle scope.
5793 v8::Debug::SetMessageHandler(NULL);
5794 CheckDebuggerUnloaded(true);
5798 // Sends continue command to the debugger.
5799 static void SendContinueCommand() {
5800 const int kBufferSize = 1000;
5801 uint16_t buffer[kBufferSize];
5802 const char* command_continue =
5804 "\"type\":\"request\","
5805 "\"command\":\"continue\"}";
5807 v8::Debug::SendCommand(
5808 CcTest::isolate(), buffer, AsciiToUtf16(command_continue, buffer));
5812 // Debugger message handler which counts the number of times it is called.
5813 static int message_handler_hit_count = 0;
5814 static void MessageHandlerHitCount(const v8::Debug::Message& message) {
5815 message_handler_hit_count++;
5817 static char print_buffer[1000];
5818 v8::String::Value json(message.GetJSON());
5819 Utf16ToAscii(*json, json.length(), print_buffer);
5820 if (IsExceptionEventMessage(print_buffer)) {
5821 // Send a continue command for exception events.
5822 SendContinueCommand();
5827 // Test clearing the debug message handler.
5828 TEST(DebuggerClearMessageHandler) {
5829 DebugLocalContext env;
5830 v8::HandleScope scope(env->GetIsolate());
5832 // Check debugger is unloaded before it is used.
5833 CheckDebuggerUnloaded();
5835 // Set a debug message handler.
5836 v8::Debug::SetMessageHandler(MessageHandlerHitCount);
5838 // Run code to throw a unhandled exception. This should end up in the message
5840 CompileRun("throw 1");
5842 // The message handler should be called.
5843 CHECK_GT(message_handler_hit_count, 0);
5845 // Clear debug message handler.
5846 message_handler_hit_count = 0;
5847 v8::Debug::SetMessageHandler(NULL);
5849 // Run code to throw a unhandled exception. This should end up in the message
5851 CompileRun("throw 1");
5853 // The message handler should not be called more.
5854 CHECK_EQ(0, message_handler_hit_count);
5856 CheckDebuggerUnloaded(true);
5860 // Debugger message handler which clears the message handler while active.
5861 static void MessageHandlerClearingMessageHandler(
5862 const v8::Debug::Message& message) {
5863 message_handler_hit_count++;
5865 // Clear debug message handler.
5866 v8::Debug::SetMessageHandler(NULL);
5870 // Test clearing the debug message handler while processing a debug event.
5871 TEST(DebuggerClearMessageHandlerWhileActive) {
5872 DebugLocalContext env;
5873 v8::HandleScope scope(env->GetIsolate());
5875 // Check debugger is unloaded before it is used.
5876 CheckDebuggerUnloaded();
5878 // Set a debug message handler.
5879 v8::Debug::SetMessageHandler(MessageHandlerClearingMessageHandler);
5881 // Run code to throw a unhandled exception. This should end up in the message
5883 CompileRun("throw 1");
5885 // The message handler should be called.
5886 CHECK_EQ(1, message_handler_hit_count);
5888 CheckDebuggerUnloaded(true);
5892 // Test for issue http://code.google.com/p/v8/issues/detail?id=289.
5893 // Make sure that DebugGetLoadedScripts doesn't return scripts
5894 // with disposed external source.
5895 class EmptyExternalStringResource : public v8::String::ExternalStringResource {
5897 EmptyExternalStringResource() { empty_[0] = 0; }
5898 virtual ~EmptyExternalStringResource() {}
5899 virtual size_t length() const { return empty_.length(); }
5900 virtual const uint16_t* data() const { return empty_.start(); }
5902 ::v8::internal::EmbeddedVector<uint16_t, 1> empty_;
5906 TEST(DebugGetLoadedScripts) {
5907 DebugLocalContext env;
5908 v8::HandleScope scope(env->GetIsolate());
5911 EmptyExternalStringResource source_ext_str;
5912 v8::Local<v8::String> source =
5913 v8::String::NewExternal(env->GetIsolate(), &source_ext_str);
5914 v8::Handle<v8::Script> evil_script(v8::Script::Compile(source));
5915 // "use" evil_script to make the compiler happy.
5917 Handle<i::ExternalTwoByteString> i_source(
5918 i::ExternalTwoByteString::cast(*v8::Utils::OpenHandle(*source)));
5919 // This situation can happen if source was an external string disposed
5921 i_source->set_resource(0);
5923 bool allow_natives_syntax = i::FLAG_allow_natives_syntax;
5924 i::FLAG_allow_natives_syntax = true;
5926 "var scripts = %DebugGetLoadedScripts();"
5927 "var count = scripts.length;"
5928 "for (var i = 0; i < count; ++i) {"
5929 " scripts[i].line_ends;"
5931 // Must not crash while accessing line_ends.
5932 i::FLAG_allow_natives_syntax = allow_natives_syntax;
5934 // Some scripts are retrieved - at least the number of native scripts.
5937 ->Get(v8::String::NewFromUtf8(env->GetIsolate(), "count"))
5943 // Test script break points set on lines.
5944 TEST(ScriptNameAndData) {
5945 DebugLocalContext env;
5946 v8::HandleScope scope(env->GetIsolate());
5949 // Create functions for retrieving script name and data for the function on
5950 // the top frame when hitting a break point.
5951 frame_script_name = CompileFunction(&env,
5952 frame_script_name_source,
5953 "frame_script_name");
5955 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
5957 // Test function source.
5958 v8::Local<v8::String> script = v8::String::NewFromUtf8(env->GetIsolate(),
5963 v8::ScriptOrigin origin1 =
5964 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "name"));
5965 v8::Handle<v8::Script> script1 = v8::Script::Compile(script, &origin1);
5967 v8::Local<v8::Function> f;
5968 f = v8::Local<v8::Function>::Cast(
5969 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
5971 f->Call(env->Global(), 0, NULL);
5972 CHECK_EQ(1, break_point_hit_count);
5973 CHECK_EQ("name", last_script_name_hit);
5975 // Compile the same script again without setting data. As the compilation
5976 // cache is disabled when debugging expect the data to be missing.
5977 v8::Script::Compile(script, &origin1)->Run();
5978 f = v8::Local<v8::Function>::Cast(
5979 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
5980 f->Call(env->Global(), 0, NULL);
5981 CHECK_EQ(2, break_point_hit_count);
5982 CHECK_EQ("name", last_script_name_hit);
5984 v8::Local<v8::String> data_obj_source = v8::String::NewFromUtf8(
5988 " toString: function() { return this.a + ' ' + this.b; }\n"
5990 v8::Script::Compile(data_obj_source)->Run();
5991 v8::ScriptOrigin origin2 =
5992 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "new name"));
5993 v8::Handle<v8::Script> script2 = v8::Script::Compile(script, &origin2);
5995 f = v8::Local<v8::Function>::Cast(
5996 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
5997 f->Call(env->Global(), 0, NULL);
5998 CHECK_EQ(3, break_point_hit_count);
5999 CHECK_EQ("new name", last_script_name_hit);
6001 v8::Handle<v8::Script> script3 = v8::Script::Compile(script, &origin2);
6003 f = v8::Local<v8::Function>::Cast(
6004 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
6005 f->Call(env->Global(), 0, NULL);
6006 CHECK_EQ(4, break_point_hit_count);
6010 static v8::Handle<v8::Context> expected_context;
6011 static v8::Handle<v8::Value> expected_context_data;
6014 // Check that the expected context is the one generating the debug event.
6015 static void ContextCheckMessageHandler(const v8::Debug::Message& message) {
6016 CHECK(message.GetEventContext() == expected_context);
6017 CHECK(message.GetEventContext()->GetEmbedderData(0)->StrictEquals(
6018 expected_context_data));
6019 message_handler_hit_count++;
6021 static char print_buffer[1000];
6022 v8::String::Value json(message.GetJSON());
6023 Utf16ToAscii(*json, json.length(), print_buffer);
6025 // Send a continue command for break events.
6026 if (IsBreakEventMessage(print_buffer)) {
6027 SendContinueCommand();
6032 // Test which creates two contexts and sets different embedder data on each.
6033 // Checks that this data is set correctly and that when the debug message
6034 // handler is called the expected context is the one active.
6036 v8::Isolate* isolate = CcTest::isolate();
6037 v8::HandleScope scope(isolate);
6039 // Create two contexts.
6040 v8::Handle<v8::Context> context_1;
6041 v8::Handle<v8::Context> context_2;
6042 v8::Handle<v8::ObjectTemplate> global_template =
6043 v8::Handle<v8::ObjectTemplate>();
6044 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>();
6045 context_1 = v8::Context::New(isolate, NULL, global_template, global_object);
6046 context_2 = v8::Context::New(isolate, NULL, global_template, global_object);
6048 v8::Debug::SetMessageHandler(ContextCheckMessageHandler);
6050 // Default data value is undefined.
6051 CHECK(context_1->GetEmbedderData(0)->IsUndefined());
6052 CHECK(context_2->GetEmbedderData(0)->IsUndefined());
6054 // Set and check different data values.
6055 v8::Handle<v8::String> data_1 = v8::String::NewFromUtf8(isolate, "1");
6056 v8::Handle<v8::String> data_2 = v8::String::NewFromUtf8(isolate, "2");
6057 context_1->SetEmbedderData(0, data_1);
6058 context_2->SetEmbedderData(0, data_2);
6059 CHECK(context_1->GetEmbedderData(0)->StrictEquals(data_1));
6060 CHECK(context_2->GetEmbedderData(0)->StrictEquals(data_2));
6062 // Simple test function which causes a break.
6063 const char* source = "function f() { debugger; }";
6065 // Enter and run function in the first context.
6067 v8::Context::Scope context_scope(context_1);
6068 expected_context = context_1;
6069 expected_context_data = data_1;
6070 v8::Local<v8::Function> f = CompileFunction(isolate, source, "f");
6071 f->Call(context_1->Global(), 0, NULL);
6075 // Enter and run function in the second context.
6077 v8::Context::Scope context_scope(context_2);
6078 expected_context = context_2;
6079 expected_context_data = data_2;
6080 v8::Local<v8::Function> f = CompileFunction(isolate, source, "f");
6081 f->Call(context_2->Global(), 0, NULL);
6084 // Two times compile event and two times break event.
6085 CHECK_GT(message_handler_hit_count, 4);
6087 v8::Debug::SetMessageHandler(NULL);
6088 CheckDebuggerUnloaded();
6092 // Debug message handler which issues a debug break when it hits a break event.
6093 static int message_handler_break_hit_count = 0;
6094 static void DebugBreakMessageHandler(const v8::Debug::Message& message) {
6095 // Schedule a debug break for break events.
6096 if (message.IsEvent() && message.GetEvent() == v8::Break) {
6097 message_handler_break_hit_count++;
6098 if (message_handler_break_hit_count == 1) {
6099 v8::Debug::DebugBreak(message.GetIsolate());
6103 // Issue a continue command if this event will not cause the VM to start
6105 if (!message.WillStartRunning()) {
6106 SendContinueCommand();
6111 // Test that a debug break can be scheduled while in a message handler.
6112 TEST(DebugBreakInMessageHandler) {
6113 DebugLocalContext env;
6114 v8::HandleScope scope(env->GetIsolate());
6116 v8::Debug::SetMessageHandler(DebugBreakMessageHandler);
6119 const char* script = "function f() { debugger; g(); } function g() { }";
6121 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
6122 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
6123 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
6124 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
6126 // Call f then g. The debugger statement in f will casue a break which will
6127 // cause another break.
6128 f->Call(env->Global(), 0, NULL);
6129 CHECK_EQ(2, message_handler_break_hit_count);
6130 // Calling g will not cause any additional breaks.
6131 g->Call(env->Global(), 0, NULL);
6132 CHECK_EQ(2, message_handler_break_hit_count);
6136 #ifndef V8_INTERPRETED_REGEXP
6137 // Debug event handler which gets the function on the top frame and schedules a
6138 // break a number of times.
6139 static void DebugEventDebugBreak(
6140 const v8::Debug::EventDetails& event_details) {
6141 v8::DebugEvent event = event_details.GetEvent();
6142 v8::Handle<v8::Object> exec_state = event_details.GetExecutionState();
6144 if (event == v8::Break) {
6145 break_point_hit_count++;
6147 // Get the name of the top frame function.
6148 if (!frame_function_name.IsEmpty()) {
6149 // Get the name of the function.
6151 v8::Handle<v8::Value> argv[argc] = {
6152 exec_state, v8::Integer::New(CcTest::isolate(), 0)
6154 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
6156 if (result->IsUndefined()) {
6157 last_function_hit[0] = '\0';
6159 CHECK(result->IsString());
6160 v8::Handle<v8::String> function_name(result->ToString());
6161 function_name->WriteUtf8(last_function_hit);
6165 // Keep forcing breaks.
6166 if (break_point_hit_count < 20) {
6167 v8::Debug::DebugBreak(CcTest::isolate());
6173 TEST(RegExpDebugBreak) {
6174 // This test only applies to native regexps.
6175 DebugLocalContext env;
6176 v8::HandleScope scope(env->GetIsolate());
6178 // Create a function for checking the function when hitting a break point.
6179 frame_function_name = CompileFunction(&env,
6180 frame_function_name_source,
6181 "frame_function_name");
6183 // Test RegExp which matches white spaces and comments at the begining of a
6185 const char* script =
6186 "var sourceLineBeginningSkip = /^(?:[ \\v\\h]*(?:\\/\\*.*?\\*\\/)*)*/;\n"
6187 "function f(s) { return s.match(sourceLineBeginningSkip)[0].length; }";
6189 v8::Local<v8::Function> f = CompileFunction(env->GetIsolate(), script, "f");
6191 v8::Handle<v8::Value> argv[argc] = {
6192 v8::String::NewFromUtf8(env->GetIsolate(), " /* xxx */ a=0;")};
6193 v8::Local<v8::Value> result = f->Call(env->Global(), argc, argv);
6194 CHECK_EQ(12, result->Int32Value());
6196 v8::Debug::SetDebugEventListener(DebugEventDebugBreak);
6197 v8::Debug::DebugBreak(env->GetIsolate());
6198 result = f->Call(env->Global(), argc, argv);
6200 // Check that there was only one break event. Matching RegExp should not
6201 // cause Break events.
6202 CHECK_EQ(1, break_point_hit_count);
6203 CHECK_EQ("f", last_function_hit);
6205 #endif // V8_INTERPRETED_REGEXP
6208 // Common part of EvalContextData and NestedBreakEventContextData tests.
6209 static void ExecuteScriptForContextCheck(
6210 v8::Debug::MessageHandler message_handler) {
6211 // Create a context.
6212 v8::Handle<v8::Context> context_1;
6213 v8::Handle<v8::ObjectTemplate> global_template =
6214 v8::Handle<v8::ObjectTemplate>();
6216 v8::Context::New(CcTest::isolate(), NULL, global_template);
6218 v8::Debug::SetMessageHandler(message_handler);
6220 // Default data value is undefined.
6221 CHECK(context_1->GetEmbedderData(0)->IsUndefined());
6223 // Set and check a data value.
6224 v8::Handle<v8::String> data_1 =
6225 v8::String::NewFromUtf8(CcTest::isolate(), "1");
6226 context_1->SetEmbedderData(0, data_1);
6227 CHECK(context_1->GetEmbedderData(0)->StrictEquals(data_1));
6229 // Simple test function with eval that causes a break.
6230 const char* source = "function f() { eval('debugger;'); }";
6232 // Enter and run function in the context.
6234 v8::Context::Scope context_scope(context_1);
6235 expected_context = context_1;
6236 expected_context_data = data_1;
6237 v8::Local<v8::Function> f = CompileFunction(CcTest::isolate(), source, "f");
6238 f->Call(context_1->Global(), 0, NULL);
6241 v8::Debug::SetMessageHandler(NULL);
6245 // Test which creates a context and sets embedder data on it. Checks that this
6246 // data is set correctly and that when the debug message handler is called for
6247 // break event in an eval statement the expected context is the one returned by
6248 // Message.GetEventContext.
6249 TEST(EvalContextData) {
6250 v8::HandleScope scope(CcTest::isolate());
6252 ExecuteScriptForContextCheck(ContextCheckMessageHandler);
6254 // One time compile event and one time break event.
6255 CHECK_GT(message_handler_hit_count, 2);
6256 CheckDebuggerUnloaded();
6260 static bool sent_eval = false;
6261 static int break_count = 0;
6262 static int continue_command_send_count = 0;
6263 // Check that the expected context is the one generating the debug event
6264 // including the case of nested break event.
6265 static void DebugEvalContextCheckMessageHandler(
6266 const v8::Debug::Message& message) {
6267 CHECK(message.GetEventContext() == expected_context);
6268 CHECK(message.GetEventContext()->GetEmbedderData(0)->StrictEquals(
6269 expected_context_data));
6270 message_handler_hit_count++;
6272 static char print_buffer[1000];
6273 v8::String::Value json(message.GetJSON());
6274 Utf16ToAscii(*json, json.length(), print_buffer);
6276 v8::Isolate* isolate = message.GetIsolate();
6277 if (IsBreakEventMessage(print_buffer)) {
6282 const int kBufferSize = 1000;
6283 uint16_t buffer[kBufferSize];
6284 const char* eval_command =
6286 "\"type\":\"request\","
6287 "\"command\":\"evaluate\","
6288 "\"arguments\":{\"expression\":\"debugger;\","
6289 "\"global\":true,\"disable_break\":false}}";
6291 // Send evaluate command.
6292 v8::Debug::SendCommand(
6293 isolate, buffer, AsciiToUtf16(eval_command, buffer));
6296 // It's a break event caused by the evaluation request above.
6297 SendContinueCommand();
6298 continue_command_send_count++;
6300 } else if (IsEvaluateResponseMessage(print_buffer) &&
6301 continue_command_send_count < 2) {
6302 // Response to the evaluation request. We're still on the breakpoint so
6304 SendContinueCommand();
6305 continue_command_send_count++;
6310 // Tests that context returned for break event is correct when the event occurs
6311 // in 'evaluate' debugger request.
6312 TEST(NestedBreakEventContextData) {
6313 v8::HandleScope scope(CcTest::isolate());
6315 message_handler_hit_count = 0;
6317 ExecuteScriptForContextCheck(DebugEvalContextCheckMessageHandler);
6319 // One time compile event and two times break event.
6320 CHECK_GT(message_handler_hit_count, 3);
6322 // One break from the source and another from the evaluate request.
6323 CHECK_EQ(break_count, 2);
6324 CheckDebuggerUnloaded();
6328 // Debug event listener which counts the after compile events.
6329 int after_compile_message_count = 0;
6330 static void AfterCompileMessageHandler(const v8::Debug::Message& message) {
6331 // Count the number of scripts collected.
6332 if (message.IsEvent()) {
6333 if (message.GetEvent() == v8::AfterCompile) {
6334 after_compile_message_count++;
6335 } else if (message.GetEvent() == v8::Break) {
6336 SendContinueCommand();
6342 // Tests that after compile event is sent as many times as there are scripts
6344 TEST(AfterCompileMessageWhenMessageHandlerIsReset) {
6345 DebugLocalContext env;
6346 v8::HandleScope scope(env->GetIsolate());
6347 after_compile_message_count = 0;
6348 const char* script = "var a=1";
6350 v8::Debug::SetMessageHandler(AfterCompileMessageHandler);
6351 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), script))
6353 v8::Debug::SetMessageHandler(NULL);
6355 v8::Debug::SetMessageHandler(AfterCompileMessageHandler);
6356 v8::Debug::DebugBreak(env->GetIsolate());
6357 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), script))
6360 // Setting listener to NULL should cause debugger unload.
6361 v8::Debug::SetMessageHandler(NULL);
6362 CheckDebuggerUnloaded();
6364 // Compilation cache should be disabled when debugger is active.
6365 CHECK_EQ(2, after_compile_message_count);
6369 // Syntax error event handler which counts a number of events.
6370 int compile_error_event_count = 0;
6372 static void CompileErrorEventCounterClear() {
6373 compile_error_event_count = 0;
6376 static void CompileErrorEventCounter(
6377 const v8::Debug::EventDetails& event_details) {
6378 v8::DebugEvent event = event_details.GetEvent();
6380 if (event == v8::CompileError) {
6381 compile_error_event_count++;
6386 // Tests that syntax error event is sent as many times as there are scripts
6387 // with syntax error compiled.
6388 TEST(SyntaxErrorMessageOnSyntaxException) {
6389 DebugLocalContext env;
6390 v8::HandleScope scope(env->GetIsolate());
6392 // For this test, we want to break on uncaught exceptions:
6393 ChangeBreakOnException(false, true);
6395 v8::Debug::SetDebugEventListener(CompileErrorEventCounter);
6397 CompileErrorEventCounterClear();
6399 // Check initial state.
6400 CHECK_EQ(0, compile_error_event_count);
6402 // Throws SyntaxError: Unexpected end of input
6403 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "+++"));
6404 CHECK_EQ(1, compile_error_event_count);
6406 v8::Script::Compile(
6407 v8::String::NewFromUtf8(env->GetIsolate(), "/sel\\/: \\"));
6408 CHECK_EQ(2, compile_error_event_count);
6410 v8::Script::Compile(
6411 v8::String::NewFromUtf8(env->GetIsolate(), "JSON.parse('1234:')"));
6412 CHECK_EQ(2, compile_error_event_count);
6414 v8::Script::Compile(
6415 v8::String::NewFromUtf8(env->GetIsolate(), "new RegExp('/\\/\\\\');"));
6416 CHECK_EQ(2, compile_error_event_count);
6418 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "throw 1;"));
6419 CHECK_EQ(2, compile_error_event_count);
6423 // Tests that break event is sent when message handler is reset.
6424 TEST(BreakMessageWhenMessageHandlerIsReset) {
6425 DebugLocalContext env;
6426 v8::HandleScope scope(env->GetIsolate());
6427 after_compile_message_count = 0;
6428 const char* script = "function f() {};";
6430 v8::Debug::SetMessageHandler(AfterCompileMessageHandler);
6431 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), script))
6433 v8::Debug::SetMessageHandler(NULL);
6435 v8::Debug::SetMessageHandler(AfterCompileMessageHandler);
6436 v8::Debug::DebugBreak(env->GetIsolate());
6437 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
6438 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
6439 f->Call(env->Global(), 0, NULL);
6441 // Setting message handler to NULL should cause debugger unload.
6442 v8::Debug::SetMessageHandler(NULL);
6443 CheckDebuggerUnloaded();
6445 // Compilation cache should be disabled when debugger is active.
6446 CHECK_EQ(1, after_compile_message_count);
6450 static int exception_event_count = 0;
6451 static void ExceptionMessageHandler(const v8::Debug::Message& message) {
6452 if (message.IsEvent() && message.GetEvent() == v8::Exception) {
6453 exception_event_count++;
6454 SendContinueCommand();
6459 // Tests that exception event is sent when message handler is reset.
6460 TEST(ExceptionMessageWhenMessageHandlerIsReset) {
6461 DebugLocalContext env;
6462 v8::HandleScope scope(env->GetIsolate());
6464 // For this test, we want to break on uncaught exceptions:
6465 ChangeBreakOnException(false, true);
6467 exception_event_count = 0;
6468 const char* script = "function f() {throw new Error()};";
6470 v8::Debug::SetMessageHandler(AfterCompileMessageHandler);
6471 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), script))
6473 v8::Debug::SetMessageHandler(NULL);
6475 v8::Debug::SetMessageHandler(ExceptionMessageHandler);
6476 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
6477 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
6478 f->Call(env->Global(), 0, NULL);
6480 // Setting message handler to NULL should cause debugger unload.
6481 v8::Debug::SetMessageHandler(NULL);
6482 CheckDebuggerUnloaded();
6484 CHECK_EQ(1, exception_event_count);
6488 // Tests after compile event is sent when there are some provisional
6489 // breakpoints out of the scripts lines range.
6490 TEST(ProvisionalBreakpointOnLineOutOfRange) {
6491 DebugLocalContext env;
6492 v8::HandleScope scope(env->GetIsolate());
6494 const char* script = "function f() {};";
6495 const char* resource_name = "test_resource";
6497 // Set a couple of provisional breakpoint on lines out of the script lines
6499 int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name,
6500 3, -1 /* no column */);
6502 SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name, 5, 5);
6504 after_compile_message_count = 0;
6505 v8::Debug::SetMessageHandler(AfterCompileMessageHandler);
6507 v8::ScriptOrigin origin(
6508 v8::String::NewFromUtf8(env->GetIsolate(), resource_name),
6509 v8::Integer::New(env->GetIsolate(), 10),
6510 v8::Integer::New(env->GetIsolate(), 1));
6511 // Compile a script whose first line number is greater than the breakpoints'
6513 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), script),
6516 // If the script is compiled successfully there is exactly one after compile
6517 // event. In case of an exception in debugger code after compile event is not
6519 CHECK_EQ(1, after_compile_message_count);
6521 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
6522 ClearBreakPointFromJS(env->GetIsolate(), sbp2);
6523 v8::Debug::SetMessageHandler(NULL);
6527 static void BreakMessageHandler(const v8::Debug::Message& message) {
6528 i::Isolate* isolate = CcTest::i_isolate();
6529 if (message.IsEvent() && message.GetEvent() == v8::Break) {
6530 // Count the number of breaks.
6531 break_point_hit_count++;
6533 i::HandleScope scope(isolate);
6536 SendContinueCommand();
6537 } else if (message.IsEvent() && message.GetEvent() == v8::AfterCompile) {
6538 i::HandleScope scope(isolate);
6540 int current_count = break_point_hit_count;
6542 // Force serialization to trigger some internal JS execution.
6545 CHECK_EQ(current_count, break_point_hit_count);
6550 // Test that if DebugBreak is forced it is ignored when code from
6551 // debug-delay.js is executed.
6552 TEST(NoDebugBreakInAfterCompileMessageHandler) {
6553 DebugLocalContext env;
6554 v8::HandleScope scope(env->GetIsolate());
6556 // Register a debug event listener which sets the break flag and counts.
6557 v8::Debug::SetMessageHandler(BreakMessageHandler);
6559 // Set the debug break flag.
6560 v8::Debug::DebugBreak(env->GetIsolate());
6562 // Create a function for testing stepping.
6563 const char* src = "function f() { eval('var x = 10;'); } ";
6564 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
6566 // There should be only one break event.
6567 CHECK_EQ(1, break_point_hit_count);
6569 // Set the debug break flag again.
6570 v8::Debug::DebugBreak(env->GetIsolate());
6571 f->Call(env->Global(), 0, NULL);
6572 // There should be one more break event when the script is evaluated in 'f'.
6573 CHECK_EQ(2, break_point_hit_count);
6575 // Get rid of the debug message handler.
6576 v8::Debug::SetMessageHandler(NULL);
6577 CheckDebuggerUnloaded();
6581 static int counting_message_handler_counter;
6583 static void CountingMessageHandler(const v8::Debug::Message& message) {
6584 if (message.IsResponse()) counting_message_handler_counter++;
6588 // Test that debug messages get processed when ProcessDebugMessages is called.
6589 TEST(ProcessDebugMessages) {
6590 DebugLocalContext env;
6591 v8::Isolate* isolate = env->GetIsolate();
6592 v8::HandleScope scope(isolate);
6594 counting_message_handler_counter = 0;
6596 v8::Debug::SetMessageHandler(CountingMessageHandler);
6598 const int kBufferSize = 1000;
6599 uint16_t buffer[kBufferSize];
6600 const char* scripts_command =
6602 "\"type\":\"request\","
6603 "\"command\":\"scripts\"}";
6605 // Send scripts command.
6606 v8::Debug::SendCommand(
6607 isolate, buffer, AsciiToUtf16(scripts_command, buffer));
6609 CHECK_EQ(0, counting_message_handler_counter);
6610 v8::Debug::ProcessDebugMessages();
6611 // At least one message should come
6612 CHECK_GE(counting_message_handler_counter, 1);
6614 counting_message_handler_counter = 0;
6616 v8::Debug::SendCommand(
6617 isolate, buffer, AsciiToUtf16(scripts_command, buffer));
6618 v8::Debug::SendCommand(
6619 isolate, buffer, AsciiToUtf16(scripts_command, buffer));
6620 CHECK_EQ(0, counting_message_handler_counter);
6621 v8::Debug::ProcessDebugMessages();
6622 // At least two messages should come
6623 CHECK_GE(counting_message_handler_counter, 2);
6625 // Get rid of the debug message handler.
6626 v8::Debug::SetMessageHandler(NULL);
6627 CheckDebuggerUnloaded();
6631 class SendCommandThread;
6632 static SendCommandThread* send_command_thread_ = NULL;
6635 class SendCommandThread : public v8::base::Thread {
6637 explicit SendCommandThread(v8::Isolate* isolate)
6638 : Thread(Options("SendCommandThread")),
6640 isolate_(isolate) {}
6642 static void CountingAndSignallingMessageHandler(
6643 const v8::Debug::Message& message) {
6644 if (message.IsResponse()) {
6645 counting_message_handler_counter++;
6646 send_command_thread_->semaphore_.Signal();
6650 virtual void Run() {
6652 const int kBufferSize = 1000;
6653 uint16_t buffer[kBufferSize];
6654 const char* scripts_command =
6656 "\"type\":\"request\","
6657 "\"command\":\"scripts\"}";
6658 int length = AsciiToUtf16(scripts_command, buffer);
6659 // Send scripts command.
6661 for (int i = 0; i < 20; i++) {
6662 v8::base::ElapsedTimer timer;
6664 CHECK_EQ(i, counting_message_handler_counter);
6665 // Queue debug message.
6666 v8::Debug::SendCommand(isolate_, buffer, length);
6667 // Wait for the message handler to pick up the response.
6669 i::PrintF("iteration %d took %f ms\n", i,
6670 timer.Elapsed().InMillisecondsF());
6673 v8::V8::TerminateExecution(isolate_);
6676 void StartSending() { semaphore_.Signal(); }
6679 v8::base::Semaphore semaphore_;
6680 v8::Isolate* isolate_;
6684 static void StartSendingCommands(
6685 const v8::FunctionCallbackInfo<v8::Value>& info) {
6686 send_command_thread_->StartSending();
6690 TEST(ProcessDebugMessagesThreaded) {
6691 DebugLocalContext env;
6692 v8::Isolate* isolate = env->GetIsolate();
6693 v8::HandleScope scope(isolate);
6695 counting_message_handler_counter = 0;
6697 v8::Debug::SetMessageHandler(
6698 SendCommandThread::CountingAndSignallingMessageHandler);
6699 send_command_thread_ = new SendCommandThread(isolate);
6700 send_command_thread_->Start();
6702 v8::Handle<v8::FunctionTemplate> start =
6703 v8::FunctionTemplate::New(isolate, StartSendingCommands);
6704 env->Global()->Set(v8_str("start"), start->GetFunction());
6706 CompileRun("start(); while (true) { }");
6708 CHECK_EQ(20, counting_message_handler_counter);
6710 v8::Debug::SetMessageHandler(NULL);
6711 CheckDebuggerUnloaded();
6715 struct BacktraceData {
6716 static int frame_counter;
6717 static void MessageHandler(const v8::Debug::Message& message) {
6718 char print_buffer[1000];
6719 v8::String::Value json(message.GetJSON());
6720 Utf16ToAscii(*json, json.length(), print_buffer, 1000);
6722 if (strstr(print_buffer, "backtrace") == NULL) {
6725 frame_counter = GetTotalFramesInt(print_buffer);
6729 int BacktraceData::frame_counter;
6732 // Test that debug messages get processed when ProcessDebugMessages is called.
6734 DebugLocalContext env;
6735 v8::Isolate* isolate = env->GetIsolate();
6736 v8::HandleScope scope(isolate);
6738 v8::Debug::SetMessageHandler(BacktraceData::MessageHandler);
6740 const int kBufferSize = 1000;
6741 uint16_t buffer[kBufferSize];
6742 const char* scripts_command =
6744 "\"type\":\"request\","
6745 "\"command\":\"backtrace\"}";
6747 // Check backtrace from ProcessDebugMessages.
6748 BacktraceData::frame_counter = -10;
6749 v8::Debug::SendCommand(
6752 AsciiToUtf16(scripts_command, buffer),
6754 v8::Debug::ProcessDebugMessages();
6755 CHECK_EQ(BacktraceData::frame_counter, 0);
6757 v8::Handle<v8::String> void0 =
6758 v8::String::NewFromUtf8(env->GetIsolate(), "void(0)");
6759 v8::Handle<v8::Script> script = CompileWithOrigin(void0, void0);
6761 // Check backtrace from "void(0)" script.
6762 BacktraceData::frame_counter = -10;
6763 v8::Debug::SendCommand(
6766 AsciiToUtf16(scripts_command, buffer),
6769 CHECK_EQ(BacktraceData::frame_counter, 1);
6771 // Get rid of the debug message handler.
6772 v8::Debug::SetMessageHandler(NULL);
6773 CheckDebuggerUnloaded();
6778 DebugLocalContext env;
6779 v8::Isolate* isolate = env->GetIsolate();
6780 v8::HandleScope scope(isolate);
6781 v8::Handle<v8::Value> obj =
6782 v8::Debug::GetMirror(v8::String::NewFromUtf8(isolate, "hodja"));
6783 v8::ScriptCompiler::Source source(v8_str(
6784 "function runTest(mirror) {"
6785 " return mirror.isString() && (mirror.length() == 5);"
6789 v8::Handle<v8::Function> run_test = v8::Handle<v8::Function>::Cast(
6790 v8::ScriptCompiler::CompileUnbound(isolate, &source)
6791 ->BindToCurrentContext()
6793 v8::Handle<v8::Value> result = run_test->Call(env->Global(), 1, &obj);
6794 CHECK(result->IsTrue());
6798 // Test that the debug break flag works with function.apply.
6799 TEST(DebugBreakFunctionApply) {
6800 DebugLocalContext env;
6801 v8::HandleScope scope(env->GetIsolate());
6803 // Create a function for testing breaking in apply.
6804 v8::Local<v8::Function> foo = CompileFunction(
6806 "function baz(x) { }"
6807 "function bar(x) { baz(); }"
6808 "function foo(){ bar.apply(this, [1]); }",
6811 // Register a debug event listener which steps and counts.
6812 v8::Debug::SetDebugEventListener(DebugEventBreakMax);
6814 // Set the debug break flag before calling the code using function.apply.
6815 v8::Debug::DebugBreak(env->GetIsolate());
6817 // Limit the number of debug breaks. This is a regression test for issue 493
6818 // where this test would enter an infinite loop.
6819 break_point_hit_count = 0;
6820 max_break_point_hit_count = 10000; // 10000 => infinite loop.
6821 foo->Call(env->Global(), 0, NULL);
6823 // When keeping the debug break several break will happen.
6824 CHECK_GT(break_point_hit_count, 1);
6826 v8::Debug::SetDebugEventListener(NULL);
6827 CheckDebuggerUnloaded();
6831 v8::Handle<v8::Context> debugee_context;
6832 v8::Handle<v8::Context> debugger_context;
6835 // Property getter that checks that current and calling contexts
6836 // are both the debugee contexts.
6837 static void NamedGetterWithCallingContextCheck(
6838 v8::Local<v8::String> name,
6839 const v8::PropertyCallbackInfo<v8::Value>& info) {
6840 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(name), "a"));
6841 v8::Handle<v8::Context> current = info.GetIsolate()->GetCurrentContext();
6842 CHECK(current == debugee_context);
6843 CHECK(current != debugger_context);
6844 v8::Handle<v8::Context> calling = info.GetIsolate()->GetCallingContext();
6845 CHECK(calling == debugee_context);
6846 CHECK(calling != debugger_context);
6847 info.GetReturnValue().Set(1);
6851 // Debug event listener that checks if the first argument of a function is
6852 // an object with property 'a' == 1. If the property has custom accessor
6853 // this handler will eventually invoke it.
6854 static void DebugEventGetAtgumentPropertyValue(
6855 const v8::Debug::EventDetails& event_details) {
6856 v8::DebugEvent event = event_details.GetEvent();
6857 v8::Handle<v8::Object> exec_state = event_details.GetExecutionState();
6858 if (event == v8::Break) {
6859 break_point_hit_count++;
6860 CHECK(debugger_context == CcTest::isolate()->GetCurrentContext());
6861 v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(CompileRun(
6862 "(function(exec_state) {\n"
6863 " return (exec_state.frame(0).argumentValue(0).property('a').\n"
6864 " value().value() == 1);\n"
6867 v8::Handle<v8::Value> argv[argc] = { exec_state };
6868 v8::Handle<v8::Value> result = func->Call(exec_state, argc, argv);
6869 CHECK(result->IsTrue());
6874 TEST(CallingContextIsNotDebugContext) {
6875 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
6876 // Create and enter a debugee context.
6877 DebugLocalContext env;
6878 v8::Isolate* isolate = env->GetIsolate();
6879 v8::HandleScope scope(isolate);
6882 // Save handles to the debugger and debugee contexts to be used in
6883 // NamedGetterWithCallingContextCheck.
6884 debugee_context = env.context();
6885 debugger_context = v8::Utils::ToLocal(debug->debug_context());
6887 // Create object with 'a' property accessor.
6888 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
6889 named->SetAccessor(v8::String::NewFromUtf8(isolate, "a"),
6890 NamedGetterWithCallingContextCheck);
6891 env->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"),
6892 named->NewInstance());
6894 // Register the debug event listener
6895 v8::Debug::SetDebugEventListener(DebugEventGetAtgumentPropertyValue);
6897 // Create a function that invokes debugger.
6898 v8::Local<v8::Function> foo = CompileFunction(
6900 "function bar(x) { debugger; }"
6901 "function foo(){ bar(obj); }",
6904 break_point_hit_count = 0;
6905 foo->Call(env->Global(), 0, NULL);
6906 CHECK_EQ(1, break_point_hit_count);
6908 v8::Debug::SetDebugEventListener(NULL);
6909 debugee_context = v8::Handle<v8::Context>();
6910 debugger_context = v8::Handle<v8::Context>();
6911 CheckDebuggerUnloaded();
6915 TEST(DebugContextIsPreservedBetweenAccesses) {
6916 v8::HandleScope scope(CcTest::isolate());
6917 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
6918 v8::Local<v8::Context> context1 = v8::Debug::GetDebugContext();
6919 v8::Local<v8::Context> context2 = v8::Debug::GetDebugContext();
6920 CHECK(v8::Utils::OpenHandle(*context1).is_identical_to(
6921 v8::Utils::OpenHandle(*context2)));
6922 v8::Debug::SetDebugEventListener(NULL);
6926 static v8::Handle<v8::Value> expected_callback_data;
6927 static void DebugEventContextChecker(const v8::Debug::EventDetails& details) {
6928 CHECK(details.GetEventContext() == expected_context);
6929 CHECK_EQ(expected_callback_data, details.GetCallbackData());
6933 // Check that event details contain context where debug event occured.
6934 TEST(DebugEventContext) {
6935 v8::Isolate* isolate = CcTest::isolate();
6936 v8::HandleScope scope(isolate);
6937 expected_context = v8::Context::New(isolate);
6938 expected_callback_data = v8::Int32::New(isolate, 2010);
6939 v8::Debug::SetDebugEventListener(DebugEventContextChecker,
6940 expected_callback_data);
6941 v8::Context::Scope context_scope(expected_context);
6942 v8::Script::Compile(
6943 v8::String::NewFromUtf8(isolate, "(function(){debugger;})();"))->Run();
6944 expected_context.Clear();
6945 v8::Debug::SetDebugEventListener(NULL);
6946 expected_context_data = v8::Handle<v8::Value>();
6947 CheckDebuggerUnloaded();
6951 static void* expected_break_data;
6952 static bool was_debug_break_called;
6953 static bool was_debug_event_called;
6954 static void DebugEventBreakDataChecker(const v8::Debug::EventDetails& details) {
6955 if (details.GetEvent() == v8::BreakForCommand) {
6956 CHECK_EQ(expected_break_data, details.GetClientData());
6957 was_debug_event_called = true;
6958 } else if (details.GetEvent() == v8::Break) {
6959 was_debug_break_called = true;
6964 // Check that event details contain context where debug event occured.
6965 TEST(DebugEventBreakData) {
6966 DebugLocalContext env;
6967 v8::Isolate* isolate = env->GetIsolate();
6968 v8::HandleScope scope(isolate);
6969 v8::Debug::SetDebugEventListener(DebugEventBreakDataChecker);
6971 TestClientData::constructor_call_counter = 0;
6972 TestClientData::destructor_call_counter = 0;
6974 expected_break_data = NULL;
6975 was_debug_event_called = false;
6976 was_debug_break_called = false;
6977 v8::Debug::DebugBreakForCommand(isolate, NULL);
6978 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
6979 "(function(x){return x;})(1);"))
6981 CHECK(was_debug_event_called);
6982 CHECK(!was_debug_break_called);
6984 TestClientData* data1 = new TestClientData();
6985 expected_break_data = data1;
6986 was_debug_event_called = false;
6987 was_debug_break_called = false;
6988 v8::Debug::DebugBreakForCommand(isolate, data1);
6989 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
6990 "(function(x){return x+1;})(1);"))
6992 CHECK(was_debug_event_called);
6993 CHECK(!was_debug_break_called);
6995 expected_break_data = NULL;
6996 was_debug_event_called = false;
6997 was_debug_break_called = false;
6998 v8::Debug::DebugBreak(isolate);
6999 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
7000 "(function(x){return x+2;})(1);"))
7002 CHECK(!was_debug_event_called);
7003 CHECK(was_debug_break_called);
7005 TestClientData* data2 = new TestClientData();
7006 expected_break_data = data2;
7007 was_debug_event_called = false;
7008 was_debug_break_called = false;
7009 v8::Debug::DebugBreak(isolate);
7010 v8::Debug::DebugBreakForCommand(isolate, data2);
7011 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
7012 "(function(x){return x+3;})(1);"))
7014 CHECK(was_debug_event_called);
7015 CHECK(was_debug_break_called);
7017 CHECK_EQ(2, TestClientData::constructor_call_counter);
7018 CHECK_EQ(TestClientData::constructor_call_counter,
7019 TestClientData::destructor_call_counter);
7021 v8::Debug::SetDebugEventListener(NULL);
7022 CheckDebuggerUnloaded();
7025 static bool debug_event_break_deoptimize_done = false;
7027 static void DebugEventBreakDeoptimize(
7028 const v8::Debug::EventDetails& event_details) {
7029 v8::DebugEvent event = event_details.GetEvent();
7030 v8::Handle<v8::Object> exec_state = event_details.GetExecutionState();
7031 if (event == v8::Break) {
7032 if (!frame_function_name.IsEmpty()) {
7033 // Get the name of the function.
7035 v8::Handle<v8::Value> argv[argc] = {
7036 exec_state, v8::Integer::New(CcTest::isolate(), 0)
7038 v8::Handle<v8::Value> result =
7039 frame_function_name->Call(exec_state, argc, argv);
7040 if (!result->IsUndefined()) {
7042 CHECK(result->IsString());
7043 v8::Handle<v8::String> function_name(result->ToString());
7044 function_name->WriteUtf8(fn);
7045 if (strcmp(fn, "bar") == 0) {
7046 i::Deoptimizer::DeoptimizeAll(CcTest::i_isolate());
7047 debug_event_break_deoptimize_done = true;
7052 v8::Debug::DebugBreak(CcTest::isolate());
7057 // Test deoptimization when execution is broken using the debug break stack
7059 TEST(DeoptimizeDuringDebugBreak) {
7060 DebugLocalContext env;
7061 v8::HandleScope scope(env->GetIsolate());
7064 // Create a function for checking the function when hitting a break point.
7065 frame_function_name = CompileFunction(&env,
7066 frame_function_name_source,
7067 "frame_function_name");
7070 // Set a debug event listener which will keep interrupting execution until
7071 // debug break. When inside function bar it will deoptimize all functions.
7072 // This tests lazy deoptimization bailout for the stack check, as the first
7073 // time in function bar when using debug break and no break points will be at
7074 // the initial stack check.
7075 v8::Debug::SetDebugEventListener(DebugEventBreakDeoptimize);
7077 // Compile and run function bar which will optimize it for some flag settings.
7078 v8::Script::Compile(v8::String::NewFromUtf8(
7079 env->GetIsolate(), "function bar(){}; bar()"))->Run();
7081 // Set debug break and call bar again.
7082 v8::Debug::DebugBreak(env->GetIsolate());
7083 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "bar()"))
7086 CHECK(debug_event_break_deoptimize_done);
7088 v8::Debug::SetDebugEventListener(NULL);
7092 static void DebugEventBreakWithOptimizedStack(
7093 const v8::Debug::EventDetails& event_details) {
7094 v8::Isolate* isolate = event_details.GetEventContext()->GetIsolate();
7095 v8::DebugEvent event = event_details.GetEvent();
7096 v8::Handle<v8::Object> exec_state = event_details.GetExecutionState();
7097 if (event == v8::Break) {
7098 if (!frame_function_name.IsEmpty()) {
7099 for (int i = 0; i < 2; i++) {
7101 v8::Handle<v8::Value> argv[argc] = {
7102 exec_state, v8::Integer::New(isolate, i)
7104 // Get the name of the function in frame i.
7105 v8::Handle<v8::Value> result =
7106 frame_function_name->Call(exec_state, argc, argv);
7107 CHECK(result->IsString());
7108 v8::Handle<v8::String> function_name(result->ToString());
7109 CHECK(function_name->Equals(v8::String::NewFromUtf8(isolate, "loop")));
7110 // Get the name of the first argument in frame i.
7111 result = frame_argument_name->Call(exec_state, argc, argv);
7112 CHECK(result->IsString());
7113 v8::Handle<v8::String> argument_name(result->ToString());
7114 CHECK(argument_name->Equals(v8::String::NewFromUtf8(isolate, "count")));
7115 // Get the value of the first argument in frame i. If the
7116 // funtion is optimized the value will be undefined, otherwise
7117 // the value will be '1 - i'.
7119 // TODO(3141533): We should be able to get the real value for
7120 // optimized frames.
7121 result = frame_argument_value->Call(exec_state, argc, argv);
7122 CHECK(result->IsUndefined() || (result->Int32Value() == 1 - i));
7123 // Get the name of the first local variable.
7124 result = frame_local_name->Call(exec_state, argc, argv);
7125 CHECK(result->IsString());
7126 v8::Handle<v8::String> local_name(result->ToString());
7127 CHECK(local_name->Equals(v8::String::NewFromUtf8(isolate, "local")));
7128 // Get the value of the first local variable. If the function
7129 // is optimized the value will be undefined, otherwise it will
7132 // TODO(3141533): We should be able to get the real value for
7133 // optimized frames.
7134 result = frame_local_value->Call(exec_state, argc, argv);
7135 CHECK(result->IsUndefined() || (result->Int32Value() == 42));
7142 static void ScheduleBreak(const v8::FunctionCallbackInfo<v8::Value>& args) {
7143 v8::Debug::SetDebugEventListener(DebugEventBreakWithOptimizedStack);
7144 v8::Debug::DebugBreak(args.GetIsolate());
7148 TEST(DebugBreakStackInspection) {
7149 DebugLocalContext env;
7150 v8::HandleScope scope(env->GetIsolate());
7152 frame_function_name =
7153 CompileFunction(&env, frame_function_name_source, "frame_function_name");
7154 frame_argument_name =
7155 CompileFunction(&env, frame_argument_name_source, "frame_argument_name");
7156 frame_argument_value = CompileFunction(&env,
7157 frame_argument_value_source,
7158 "frame_argument_value");
7160 CompileFunction(&env, frame_local_name_source, "frame_local_name");
7162 CompileFunction(&env, frame_local_value_source, "frame_local_value");
7164 v8::Handle<v8::FunctionTemplate> schedule_break_template =
7165 v8::FunctionTemplate::New(env->GetIsolate(), ScheduleBreak);
7166 v8::Handle<v8::Function> schedule_break =
7167 schedule_break_template->GetFunction();
7168 env->Global()->Set(v8_str("scheduleBreak"), schedule_break);
7171 "function loop(count) {"
7173 " if (count < 1) { scheduleBreak(); loop(count + 1); }"
7176 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), src))->Run();
7180 // Test that setting the terminate execution flag during debug break processing.
7181 static void TestDebugBreakInLoop(const char* loop_head,
7182 const char** loop_bodies,
7183 const char* loop_tail) {
7184 // Receive 100 breaks for each test and then terminate JavaScript execution.
7185 static const int kBreaksPerTest = 100;
7187 for (int i = 0; loop_bodies[i] != NULL; i++) {
7188 // Perform a lazy deoptimization after various numbers of breaks
7190 for (int j = 0; j < 7; j++) {
7191 break_point_hit_count_deoptimize = j;
7193 break_point_hit_count_deoptimize = kBreaksPerTest;
7196 break_point_hit_count = 0;
7197 max_break_point_hit_count = kBreaksPerTest;
7198 terminate_after_max_break_point_hit = true;
7200 EmbeddedVector<char, 1024> buffer;
7202 "function f() {%s%s%s}",
7203 loop_head, loop_bodies[i], loop_tail);
7205 // Function with infinite loop.
7206 CompileRun(buffer.start());
7208 // Set the debug break to enter the debugger as soon as possible.
7209 v8::Debug::DebugBreak(CcTest::isolate());
7211 // Call function with infinite loop.
7213 CHECK_EQ(kBreaksPerTest, break_point_hit_count);
7215 CHECK(!v8::V8::IsExecutionTerminating());
7221 TEST(DebugBreakLoop) {
7222 DebugLocalContext env;
7223 v8::HandleScope scope(env->GetIsolate());
7225 // Register a debug event listener which sets the break flag and counts.
7226 v8::Debug::SetDebugEventListener(DebugEventBreakMax);
7228 // Create a function for getting the frame count when hitting the break.
7229 frame_count = CompileFunction(&env, frame_count_source, "frame_count");
7231 CompileRun("var a = 1;");
7232 CompileRun("function g() { }");
7233 CompileRun("function h() { }");
7235 const char* loop_bodies[] = {
7238 "if (a == 0) { g() }",
7239 "if (a == 1) { g() }",
7240 "if (a == 0) { g() } else { h() }",
7241 "if (a == 0) { continue }",
7242 "if (a == 1) { continue }",
7243 "switch (a) { case 1: g(); }",
7244 "switch (a) { case 1: continue; }",
7245 "switch (a) { case 1: g(); break; default: h() }",
7246 "switch (a) { case 1: continue; break; default: h() }",
7250 TestDebugBreakInLoop("while (true) {", loop_bodies, "}");
7251 TestDebugBreakInLoop("while (a == 1) {", loop_bodies, "}");
7253 TestDebugBreakInLoop("do {", loop_bodies, "} while (true)");
7254 TestDebugBreakInLoop("do {", loop_bodies, "} while (a == 1)");
7256 TestDebugBreakInLoop("for (;;) {", loop_bodies, "}");
7257 TestDebugBreakInLoop("for (;a == 1;) {", loop_bodies, "}");
7259 // Get rid of the debug event listener.
7260 v8::Debug::SetDebugEventListener(NULL);
7261 CheckDebuggerUnloaded();
7265 v8::Local<v8::Script> inline_script;
7267 static void DebugBreakInlineListener(
7268 const v8::Debug::EventDetails& event_details) {
7269 v8::DebugEvent event = event_details.GetEvent();
7270 if (event != v8::Break) return;
7272 int expected_frame_count = 4;
7273 int expected_line_number[] = {1, 4, 7, 12};
7275 i::Handle<i::Object> compiled_script = v8::Utils::OpenHandle(*inline_script);
7276 i::Handle<i::Script> source_script = i::Handle<i::Script>(i::Script::cast(
7277 i::JSFunction::cast(*compiled_script)->shared()->script()));
7279 int break_id = CcTest::i_isolate()->debug()->break_id();
7281 i::Vector<char> script_vector(script, sizeof(script));
7282 SNPrintF(script_vector, "%%GetFrameCount(%d)", break_id);
7283 v8::Local<v8::Value> result = CompileRun(script);
7285 int frame_count = result->Int32Value();
7286 CHECK_EQ(expected_frame_count, frame_count);
7288 for (int i = 0; i < frame_count; i++) {
7289 // The 5. element in the returned array of GetFrameDetails contains the
7290 // source position of that frame.
7291 SNPrintF(script_vector, "%%GetFrameDetails(%d, %d)[5]", break_id, i);
7292 v8::Local<v8::Value> result = CompileRun(script);
7293 CHECK_EQ(expected_line_number[i],
7294 i::Script::GetLineNumber(source_script, result->Int32Value()));
7296 v8::Debug::SetDebugEventListener(NULL);
7297 v8::V8::TerminateExecution(CcTest::isolate());
7301 TEST(DebugBreakInline) {
7302 i::FLAG_allow_natives_syntax = true;
7303 DebugLocalContext env;
7304 v8::HandleScope scope(env->GetIsolate());
7305 const char* source =
7306 "function debug(b) { \n"
7307 " if (b) debugger; \n"
7309 "function f(b) { \n"
7312 "function g(b) { \n"
7317 "%OptimizeFunctionOnNextCall(g); \n"
7319 v8::Debug::SetDebugEventListener(DebugBreakInlineListener);
7321 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), source));
7322 inline_script->Run();
7326 static void DebugEventStepNext(
7327 const v8::Debug::EventDetails& event_details) {
7328 v8::DebugEvent event = event_details.GetEvent();
7329 if (event == v8::Break) {
7330 PrepareStep(StepNext);
7335 static void RunScriptInANewCFrame(const char* source) {
7336 v8::TryCatch try_catch;
7338 CHECK(try_catch.HasCaught());
7342 TEST(Regress131642) {
7344 // When doing StepNext through the first script, the debugger is not reset
7345 // after exiting through exception. A flawed implementation enabling the
7346 // debugger to step into Array.prototype.forEach breaks inside the callback
7347 // for forEach in the second script under the assumption that we are in a
7348 // recursive call. In an attempt to step out, we crawl the stack using the
7349 // recorded frame pointer from the first script and fail when not finding it
7351 DebugLocalContext env;
7352 v8::HandleScope scope(env->GetIsolate());
7353 v8::Debug::SetDebugEventListener(DebugEventStepNext);
7355 // We step through the first script. It exits through an exception. We run
7356 // this inside a new frame to record a different FP than the second script
7358 const char* script_1 = "debugger; throw new Error();";
7359 RunScriptInANewCFrame(script_1);
7361 // The second script uses forEach.
7362 const char* script_2 = "[0].forEach(function() { });";
7363 CompileRun(script_2);
7365 v8::Debug::SetDebugEventListener(NULL);
7369 // Import from test-heap.cc
7370 int CountNativeContexts();
7373 static void NopListener(const v8::Debug::EventDetails& event_details) {
7377 TEST(DebuggerCreatesContextIffActive) {
7378 DebugLocalContext env;
7379 v8::HandleScope scope(env->GetIsolate());
7380 CHECK_EQ(1, CountNativeContexts());
7382 v8::Debug::SetDebugEventListener(NULL);
7383 CompileRun("debugger;");
7384 CHECK_EQ(1, CountNativeContexts());
7386 v8::Debug::SetDebugEventListener(NopListener);
7387 CompileRun("debugger;");
7388 CHECK_EQ(2, CountNativeContexts());
7390 v8::Debug::SetDebugEventListener(NULL);
7394 TEST(LiveEditEnabled) {
7395 v8::internal::FLAG_allow_natives_syntax = true;
7397 v8::HandleScope scope(env->GetIsolate());
7398 v8::Debug::SetLiveEditEnabled(env->GetIsolate(), true);
7399 CompileRun("%LiveEditCompareStrings('', '')");
7403 TEST(LiveEditDisabled) {
7404 v8::internal::FLAG_allow_natives_syntax = true;
7406 v8::HandleScope scope(env->GetIsolate());
7407 v8::Debug::SetLiveEditEnabled(env->GetIsolate(), false);
7408 CompileRun("%LiveEditCompareStrings('', '')");
7412 TEST(PrecompiledFunction) {
7413 // Regression test for crbug.com/346207. If we have preparse data, parsing the
7414 // function in the presence of the debugger (and breakpoints) should still
7415 // succeed. The bug was that preparsing was done lazily and parsing was done
7416 // eagerly, so, the symbol streams didn't match.
7417 DebugLocalContext env;
7418 v8::HandleScope scope(env->GetIsolate());
7420 v8::Debug::SetDebugEventListener(DebugBreakInlineListener);
7422 v8::Local<v8::Function> break_here =
7423 CompileFunction(&env, "function break_here(){}", "break_here");
7424 SetBreakPoint(break_here, 0);
7426 const char* source =
7427 "var a = b = c = 1; \n"
7428 "function this_is_lazy() { \n"
7429 // This symbol won't appear in the preparse data.
7432 "function bar() { \n"
7433 " return \"bar\"; \n"
7437 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
7438 CHECK(result->IsString());
7439 v8::String::Utf8Value utf8(result);
7440 CHECK_EQ("bar", *utf8);
7442 v8::Debug::SetDebugEventListener(NULL);
7443 CheckDebuggerUnloaded();
7447 static void DebugBreakStackTraceListener(
7448 const v8::Debug::EventDetails& event_details) {
7449 v8::StackTrace::CurrentStackTrace(CcTest::isolate(), 10);
7453 static void AddDebugBreak(const v8::FunctionCallbackInfo<v8::Value>& args) {
7454 v8::Debug::DebugBreak(args.GetIsolate());
7458 TEST(DebugBreakStackTrace) {
7459 DebugLocalContext env;
7460 v8::HandleScope scope(env->GetIsolate());
7461 v8::Debug::SetDebugEventListener(DebugBreakStackTraceListener);
7462 v8::Handle<v8::FunctionTemplate> add_debug_break_template =
7463 v8::FunctionTemplate::New(env->GetIsolate(), AddDebugBreak);
7464 v8::Handle<v8::Function> add_debug_break =
7465 add_debug_break_template->GetFunction();
7466 env->Global()->Set(v8_str("add_debug_break"), add_debug_break);
7468 CompileRun("(function loop() {"
7469 " for (var j = 0; j < 1000; j++) {"
7470 " for (var i = 0; i < 1000; i++) {"
7471 " if (i == 999) add_debug_break();"
7478 v8::base::Semaphore terminate_requested_semaphore(0);
7479 v8::base::Semaphore terminate_fired_semaphore(0);
7480 bool terminate_already_fired = false;
7483 static void DebugBreakTriggerTerminate(
7484 const v8::Debug::EventDetails& event_details) {
7485 if (event_details.GetEvent() != v8::Break || terminate_already_fired) return;
7486 terminate_requested_semaphore.Signal();
7487 // Wait for at most 2 seconds for the terminate request.
7488 CHECK(terminate_fired_semaphore.WaitFor(v8::base::TimeDelta::FromSeconds(2)));
7489 terminate_already_fired = true;
7493 class TerminationThread : public v8::base::Thread {
7495 explicit TerminationThread(v8::Isolate* isolate)
7496 : Thread(Options("terminator")), isolate_(isolate) {}
7498 virtual void Run() {
7499 terminate_requested_semaphore.Wait();
7500 v8::V8::TerminateExecution(isolate_);
7501 terminate_fired_semaphore.Signal();
7505 v8::Isolate* isolate_;
7509 TEST(DebugBreakOffThreadTerminate) {
7510 DebugLocalContext env;
7511 v8::Isolate* isolate = env->GetIsolate();
7512 v8::HandleScope scope(isolate);
7513 v8::Debug::SetDebugEventListener(DebugBreakTriggerTerminate);
7514 TerminationThread terminator(isolate);
7516 v8::TryCatch try_catch;
7517 v8::Debug::DebugBreak(isolate);
7518 CompileRun("while (true);");
7519 CHECK(try_catch.HasTerminated());