blob: 5b7219301ee4892a5ffcf38589151ca58abe5fde [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2007-2008 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
4// met:
5//
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.
15//
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.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "api.h"
33#include "compilation-cache.h"
34#include "debug.h"
35#include "platform.h"
36#include "stub-cache.h"
37#include "cctest.h"
38
39
40using ::v8::internal::EmbeddedVector;
41using ::v8::internal::Object;
42using ::v8::internal::OS;
43using ::v8::internal::Handle;
44using ::v8::internal::Heap;
45using ::v8::internal::JSGlobalProxy;
46using ::v8::internal::Code;
47using ::v8::internal::Debug;
48using ::v8::internal::Debugger;
49using ::v8::internal::CommandMessage;
50using ::v8::internal::CommandMessageQueue;
51using ::v8::internal::StepAction;
52using ::v8::internal::StepIn; // From StepAction enum
53using ::v8::internal::StepNext; // From StepAction enum
54using ::v8::internal::StepOut; // From StepAction enum
55using ::v8::internal::Vector;
Steve Blockd0582a62009-12-15 09:54:21 +000056using ::v8::internal::StrLength;
Steve Blocka7e24c12009-10-30 11:49:00 +000057
58// Size of temp buffer for formatting small strings.
59#define SMALL_STRING_BUFFER_SIZE 80
60
61// --- A d d i t i o n a l C h e c k H e l p e r s
62
63
64// Helper function used by the CHECK_EQ function when given Address
65// arguments. Should not be called directly.
66static inline void CheckEqualsHelper(const char* file, int line,
67 const char* expected_source,
68 ::v8::internal::Address expected,
69 const char* value_source,
70 ::v8::internal::Address value) {
71 if (expected != value) {
72 V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n# "
73 "Expected: %i\n# Found: %i",
74 expected_source, value_source, expected, value);
75 }
76}
77
78
79// Helper function used by the CHECK_NE function when given Address
80// arguments. Should not be called directly.
81static inline void CheckNonEqualsHelper(const char* file, int line,
82 const char* unexpected_source,
83 ::v8::internal::Address unexpected,
84 const char* value_source,
85 ::v8::internal::Address value) {
86 if (unexpected == value) {
87 V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %i",
88 unexpected_source, value_source, value);
89 }
90}
91
92
93// Helper function used by the CHECK function when given code
94// arguments. Should not be called directly.
95static inline void CheckEqualsHelper(const char* file, int line,
96 const char* expected_source,
97 const Code* expected,
98 const char* value_source,
99 const Code* value) {
100 if (expected != value) {
101 V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n# "
102 "Expected: %p\n# Found: %p",
103 expected_source, value_source, expected, value);
104 }
105}
106
107
108static inline void CheckNonEqualsHelper(const char* file, int line,
109 const char* expected_source,
110 const Code* expected,
111 const char* value_source,
112 const Code* value) {
113 if (expected == value) {
114 V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %p",
115 expected_source, value_source, value);
116 }
117}
118
119
120// --- H e l p e r C l a s s e s
121
122
123// Helper class for creating a V8 enviromnent for running tests
124class DebugLocalContext {
125 public:
126 inline DebugLocalContext(
127 v8::ExtensionConfiguration* extensions = 0,
128 v8::Handle<v8::ObjectTemplate> global_template =
129 v8::Handle<v8::ObjectTemplate>(),
130 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>())
131 : context_(v8::Context::New(extensions, global_template, global_object)) {
132 context_->Enter();
133 }
134 inline ~DebugLocalContext() {
135 context_->Exit();
136 context_.Dispose();
137 }
138 inline v8::Context* operator->() { return *context_; }
139 inline v8::Context* operator*() { return *context_; }
140 inline bool IsReady() { return !context_.IsEmpty(); }
141 void ExposeDebug() {
142 // Expose the debug context global object in the global object for testing.
143 Debug::Load();
144 Debug::debug_context()->set_security_token(
145 v8::Utils::OpenHandle(*context_)->security_token());
146
147 Handle<JSGlobalProxy> global(Handle<JSGlobalProxy>::cast(
148 v8::Utils::OpenHandle(*context_->Global())));
149 Handle<v8::internal::String> debug_string =
150 v8::internal::Factory::LookupAsciiSymbol("debug");
151 SetProperty(global, debug_string,
152 Handle<Object>(Debug::debug_context()->global_proxy()), DONT_ENUM);
153 }
154 private:
155 v8::Persistent<v8::Context> context_;
156};
157
158
159// --- H e l p e r F u n c t i o n s
160
161
162// Compile and run the supplied source and return the fequested function.
163static v8::Local<v8::Function> CompileFunction(DebugLocalContext* env,
164 const char* source,
165 const char* function_name) {
166 v8::Script::Compile(v8::String::New(source))->Run();
167 return v8::Local<v8::Function>::Cast(
168 (*env)->Global()->Get(v8::String::New(function_name)));
169}
170
171
172// Compile and run the supplied source and return the requested function.
173static v8::Local<v8::Function> CompileFunction(const char* source,
174 const char* function_name) {
175 v8::Script::Compile(v8::String::New(source))->Run();
176 return v8::Local<v8::Function>::Cast(
177 v8::Context::GetCurrent()->Global()->Get(v8::String::New(function_name)));
178}
179
180
Steve Blocka7e24c12009-10-30 11:49:00 +0000181// Is there any debug info for the function?
182static bool HasDebugInfo(v8::Handle<v8::Function> fun) {
183 Handle<v8::internal::JSFunction> f = v8::Utils::OpenHandle(*fun);
184 Handle<v8::internal::SharedFunctionInfo> shared(f->shared());
185 return Debug::HasDebugInfo(shared);
186}
187
188
189// Set a break point in a function and return the associated break point
190// number.
191static int SetBreakPoint(Handle<v8::internal::JSFunction> fun, int position) {
192 static int break_point = 0;
193 Handle<v8::internal::SharedFunctionInfo> shared(fun->shared());
194 Debug::SetBreakPoint(
195 shared, position,
196 Handle<Object>(v8::internal::Smi::FromInt(++break_point)));
197 return break_point;
198}
199
200
201// Set a break point in a function and return the associated break point
202// number.
203static int SetBreakPoint(v8::Handle<v8::Function> fun, int position) {
204 return SetBreakPoint(v8::Utils::OpenHandle(*fun), position);
205}
206
207
208// Set a break point in a function using the Debug object and return the
209// associated break point number.
210static int SetBreakPointFromJS(const char* function_name,
211 int line, int position) {
212 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
213 OS::SNPrintF(buffer,
214 "debug.Debug.setBreakPoint(%s,%d,%d)",
215 function_name, line, position);
216 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
217 v8::Handle<v8::String> str = v8::String::New(buffer.start());
218 return v8::Script::Compile(str)->Run()->Int32Value();
219}
220
221
222// Set a break point in a script identified by id using the global Debug object.
223static int SetScriptBreakPointByIdFromJS(int script_id, int line, int column) {
224 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
225 if (column >= 0) {
226 // Column specified set script break point on precise location.
227 OS::SNPrintF(buffer,
228 "debug.Debug.setScriptBreakPointById(%d,%d,%d)",
229 script_id, line, column);
230 } else {
231 // Column not specified set script break point on line.
232 OS::SNPrintF(buffer,
233 "debug.Debug.setScriptBreakPointById(%d,%d)",
234 script_id, line);
235 }
236 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
237 {
238 v8::TryCatch try_catch;
239 v8::Handle<v8::String> str = v8::String::New(buffer.start());
240 v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run();
241 CHECK(!try_catch.HasCaught());
242 return value->Int32Value();
243 }
244}
245
246
247// Set a break point in a script identified by name using the global Debug
248// object.
249static int SetScriptBreakPointByNameFromJS(const char* script_name,
250 int line, int column) {
251 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
252 if (column >= 0) {
253 // Column specified set script break point on precise location.
254 OS::SNPrintF(buffer,
255 "debug.Debug.setScriptBreakPointByName(\"%s\",%d,%d)",
256 script_name, line, column);
257 } else {
258 // Column not specified set script break point on line.
259 OS::SNPrintF(buffer,
260 "debug.Debug.setScriptBreakPointByName(\"%s\",%d)",
261 script_name, line);
262 }
263 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
264 {
265 v8::TryCatch try_catch;
266 v8::Handle<v8::String> str = v8::String::New(buffer.start());
267 v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run();
268 CHECK(!try_catch.HasCaught());
269 return value->Int32Value();
270 }
271}
272
273
274// Clear a break point.
275static void ClearBreakPoint(int break_point) {
276 Debug::ClearBreakPoint(
277 Handle<Object>(v8::internal::Smi::FromInt(break_point)));
278}
279
280
281// Clear a break point using the global Debug object.
282static void ClearBreakPointFromJS(int break_point_number) {
283 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
284 OS::SNPrintF(buffer,
285 "debug.Debug.clearBreakPoint(%d)",
286 break_point_number);
287 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
288 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
289}
290
291
292static void EnableScriptBreakPointFromJS(int break_point_number) {
293 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
294 OS::SNPrintF(buffer,
295 "debug.Debug.enableScriptBreakPoint(%d)",
296 break_point_number);
297 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
298 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
299}
300
301
302static void DisableScriptBreakPointFromJS(int break_point_number) {
303 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
304 OS::SNPrintF(buffer,
305 "debug.Debug.disableScriptBreakPoint(%d)",
306 break_point_number);
307 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
308 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
309}
310
311
312static void ChangeScriptBreakPointConditionFromJS(int break_point_number,
313 const char* condition) {
314 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
315 OS::SNPrintF(buffer,
316 "debug.Debug.changeScriptBreakPointCondition(%d, \"%s\")",
317 break_point_number, condition);
318 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
319 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
320}
321
322
323static void ChangeScriptBreakPointIgnoreCountFromJS(int break_point_number,
324 int ignoreCount) {
325 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
326 OS::SNPrintF(buffer,
327 "debug.Debug.changeScriptBreakPointIgnoreCount(%d, %d)",
328 break_point_number, ignoreCount);
329 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
330 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
331}
332
333
334// Change break on exception.
335static void ChangeBreakOnException(bool caught, bool uncaught) {
336 Debug::ChangeBreakOnException(v8::internal::BreakException, caught);
337 Debug::ChangeBreakOnException(v8::internal::BreakUncaughtException, uncaught);
338}
339
340
341// Change break on exception using the global Debug object.
342static void ChangeBreakOnExceptionFromJS(bool caught, bool uncaught) {
343 if (caught) {
344 v8::Script::Compile(
345 v8::String::New("debug.Debug.setBreakOnException()"))->Run();
346 } else {
347 v8::Script::Compile(
348 v8::String::New("debug.Debug.clearBreakOnException()"))->Run();
349 }
350 if (uncaught) {
351 v8::Script::Compile(
352 v8::String::New("debug.Debug.setBreakOnUncaughtException()"))->Run();
353 } else {
354 v8::Script::Compile(
355 v8::String::New("debug.Debug.clearBreakOnUncaughtException()"))->Run();
356 }
357}
358
359
360// Prepare to step to next break location.
361static void PrepareStep(StepAction step_action) {
362 Debug::PrepareStep(step_action, 1);
363}
364
365
366// This function is in namespace v8::internal to be friend with class
367// v8::internal::Debug.
368namespace v8 {
369namespace internal {
370
371// Collect the currently debugged functions.
372Handle<FixedArray> GetDebuggedFunctions() {
373 v8::internal::DebugInfoListNode* node = Debug::debug_info_list_;
374
375 // Find the number of debugged functions.
376 int count = 0;
377 while (node) {
378 count++;
379 node = node->next();
380 }
381
382 // Allocate array for the debugged functions
383 Handle<FixedArray> debugged_functions =
384 v8::internal::Factory::NewFixedArray(count);
385
386 // Run through the debug info objects and collect all functions.
387 count = 0;
388 while (node) {
389 debugged_functions->set(count++, *node->debug_info());
390 node = node->next();
391 }
392
393 return debugged_functions;
394}
395
396
397static Handle<Code> ComputeCallDebugBreak(int argc) {
398 CALL_HEAP_FUNCTION(v8::internal::StubCache::ComputeCallDebugBreak(argc),
399 Code);
400}
401
402
403// Check that the debugger has been fully unloaded.
404void CheckDebuggerUnloaded(bool check_functions) {
405 // Check that the debugger context is cleared and that there is no debug
406 // information stored for the debugger.
407 CHECK(Debug::debug_context().is_null());
408 CHECK_EQ(NULL, Debug::debug_info_list_);
409
410 // Collect garbage to ensure weak handles are cleared.
411 Heap::CollectAllGarbage(false);
412 Heap::CollectAllGarbage(false);
413
414 // Iterate the head and check that there are no debugger related objects left.
415 HeapIterator iterator;
416 while (iterator.has_next()) {
417 HeapObject* obj = iterator.next();
418 CHECK(obj != NULL);
419 CHECK(!obj->IsDebugInfo());
420 CHECK(!obj->IsBreakPointInfo());
421
422 // If deep check of functions is requested check that no debug break code
423 // is left in all functions.
424 if (check_functions) {
425 if (obj->IsJSFunction()) {
426 JSFunction* fun = JSFunction::cast(obj);
427 for (RelocIterator it(fun->shared()->code()); !it.done(); it.next()) {
428 RelocInfo::Mode rmode = it.rinfo()->rmode();
429 if (RelocInfo::IsCodeTarget(rmode)) {
430 CHECK(!Debug::IsDebugBreak(it.rinfo()->target_address()));
431 } else if (RelocInfo::IsJSReturn(rmode)) {
432 CHECK(!Debug::IsDebugBreakAtReturn(it.rinfo()));
433 }
434 }
435 }
436 }
437 }
438}
439
440
441} } // namespace v8::internal
442
443
444// Check that the debugger has been fully unloaded.
445static void CheckDebuggerUnloaded(bool check_functions = false) {
446 v8::internal::CheckDebuggerUnloaded(check_functions);
447}
448
449
450// Inherit from BreakLocationIterator to get access to protected parts for
451// testing.
452class TestBreakLocationIterator: public v8::internal::BreakLocationIterator {
453 public:
454 explicit TestBreakLocationIterator(Handle<v8::internal::DebugInfo> debug_info)
455 : BreakLocationIterator(debug_info, v8::internal::SOURCE_BREAK_LOCATIONS) {}
456 v8::internal::RelocIterator* it() { return reloc_iterator_; }
457 v8::internal::RelocIterator* it_original() {
458 return reloc_iterator_original_;
459 }
460};
461
462
463// Compile a function, set a break point and check that the call at the break
464// location in the code is the expected debug_break function.
465void CheckDebugBreakFunction(DebugLocalContext* env,
466 const char* source, const char* name,
467 int position, v8::internal::RelocInfo::Mode mode,
468 Code* debug_break) {
469 // Create function and set the break point.
470 Handle<v8::internal::JSFunction> fun = v8::Utils::OpenHandle(
471 *CompileFunction(env, source, name));
472 int bp = SetBreakPoint(fun, position);
473
474 // Check that the debug break function is as expected.
475 Handle<v8::internal::SharedFunctionInfo> shared(fun->shared());
476 CHECK(Debug::HasDebugInfo(shared));
477 TestBreakLocationIterator it1(Debug::GetDebugInfo(shared));
478 it1.FindBreakLocationFromPosition(position);
479 CHECK_EQ(mode, it1.it()->rinfo()->rmode());
480 if (mode != v8::internal::RelocInfo::JS_RETURN) {
481 CHECK_EQ(debug_break,
482 Code::GetCodeFromTargetAddress(it1.it()->rinfo()->target_address()));
483 } else {
484 CHECK(Debug::IsDebugBreakAtReturn(it1.it()->rinfo()));
485 }
486
487 // Clear the break point and check that the debug break function is no longer
488 // there
489 ClearBreakPoint(bp);
490 CHECK(!Debug::HasDebugInfo(shared));
491 CHECK(Debug::EnsureDebugInfo(shared));
492 TestBreakLocationIterator it2(Debug::GetDebugInfo(shared));
493 it2.FindBreakLocationFromPosition(position);
494 CHECK_EQ(mode, it2.it()->rinfo()->rmode());
495 if (mode == v8::internal::RelocInfo::JS_RETURN) {
496 CHECK(!Debug::IsDebugBreakAtReturn(it2.it()->rinfo()));
497 }
498}
499
500
501// --- D e b u g E v e n t H a n d l e r s
502// ---
503// --- The different tests uses a number of debug event handlers.
504// ---
505
506
507// Source for The JavaScript function which picks out the function name of the
508// top frame.
509const char* frame_function_name_source =
510 "function frame_function_name(exec_state) {"
511 " return exec_state.frame(0).func().name();"
512 "}";
513v8::Local<v8::Function> frame_function_name;
514
515
516// Source for The JavaScript function which picks out the source line for the
517// top frame.
518const char* frame_source_line_source =
519 "function frame_source_line(exec_state) {"
520 " return exec_state.frame(0).sourceLine();"
521 "}";
522v8::Local<v8::Function> frame_source_line;
523
524
525// Source for The JavaScript function which picks out the source column for the
526// top frame.
527const char* frame_source_column_source =
528 "function frame_source_column(exec_state) {"
529 " return exec_state.frame(0).sourceColumn();"
530 "}";
531v8::Local<v8::Function> frame_source_column;
532
533
534// Source for The JavaScript function which picks out the script name for the
535// top frame.
536const char* frame_script_name_source =
537 "function frame_script_name(exec_state) {"
538 " return exec_state.frame(0).func().script().name();"
539 "}";
540v8::Local<v8::Function> frame_script_name;
541
542
543// Source for The JavaScript function which picks out the script data for the
544// top frame.
545const char* frame_script_data_source =
546 "function frame_script_data(exec_state) {"
547 " return exec_state.frame(0).func().script().data();"
548 "}";
549v8::Local<v8::Function> frame_script_data;
550
551
552// Source for The JavaScript function which returns the number of frames.
553static const char* frame_count_source =
554 "function frame_count(exec_state) {"
555 " return exec_state.frameCount();"
556 "}";
557v8::Handle<v8::Function> frame_count;
558
559
560// Global variable to store the last function hit - used by some tests.
561char last_function_hit[80];
562
563// Global variable to store the name and data for last script hit - used by some
564// tests.
565char last_script_name_hit[80];
566char last_script_data_hit[80];
567
568// Global variables to store the last source position - used by some tests.
569int last_source_line = -1;
570int last_source_column = -1;
571
572// Debug event handler which counts the break points which have been hit.
573int break_point_hit_count = 0;
574static void DebugEventBreakPointHitCount(v8::DebugEvent event,
575 v8::Handle<v8::Object> exec_state,
576 v8::Handle<v8::Object> event_data,
577 v8::Handle<v8::Value> data) {
578 // When hitting a debug event listener there must be a break set.
579 CHECK_NE(v8::internal::Debug::break_id(), 0);
580
581 // Count the number of breaks.
582 if (event == v8::Break) {
583 break_point_hit_count++;
584 if (!frame_function_name.IsEmpty()) {
585 // Get the name of the function.
586 const int argc = 1;
587 v8::Handle<v8::Value> argv[argc] = { exec_state };
588 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
589 argc, argv);
590 if (result->IsUndefined()) {
591 last_function_hit[0] = '\0';
592 } else {
593 CHECK(result->IsString());
594 v8::Handle<v8::String> function_name(result->ToString());
595 function_name->WriteAscii(last_function_hit);
596 }
597 }
598
599 if (!frame_source_line.IsEmpty()) {
600 // Get the source line.
601 const int argc = 1;
602 v8::Handle<v8::Value> argv[argc] = { exec_state };
603 v8::Handle<v8::Value> result = frame_source_line->Call(exec_state,
604 argc, argv);
605 CHECK(result->IsNumber());
606 last_source_line = result->Int32Value();
607 }
608
609 if (!frame_source_column.IsEmpty()) {
610 // Get the source column.
611 const int argc = 1;
612 v8::Handle<v8::Value> argv[argc] = { exec_state };
613 v8::Handle<v8::Value> result = frame_source_column->Call(exec_state,
614 argc, argv);
615 CHECK(result->IsNumber());
616 last_source_column = result->Int32Value();
617 }
618
619 if (!frame_script_name.IsEmpty()) {
620 // Get the script name of the function script.
621 const int argc = 1;
622 v8::Handle<v8::Value> argv[argc] = { exec_state };
623 v8::Handle<v8::Value> result = frame_script_name->Call(exec_state,
624 argc, argv);
625 if (result->IsUndefined()) {
626 last_script_name_hit[0] = '\0';
627 } else {
628 CHECK(result->IsString());
629 v8::Handle<v8::String> script_name(result->ToString());
630 script_name->WriteAscii(last_script_name_hit);
631 }
632 }
633
634 if (!frame_script_data.IsEmpty()) {
635 // Get the script data of the function script.
636 const int argc = 1;
637 v8::Handle<v8::Value> argv[argc] = { exec_state };
638 v8::Handle<v8::Value> result = frame_script_data->Call(exec_state,
639 argc, argv);
640 if (result->IsUndefined()) {
641 last_script_data_hit[0] = '\0';
642 } else {
643 result = result->ToString();
644 CHECK(result->IsString());
645 v8::Handle<v8::String> script_data(result->ToString());
646 script_data->WriteAscii(last_script_data_hit);
647 }
648 }
649 }
650}
651
652
653// Debug event handler which counts a number of events and collects the stack
654// height if there is a function compiled for that.
655int exception_hit_count = 0;
656int uncaught_exception_hit_count = 0;
657int last_js_stack_height = -1;
658
659static void DebugEventCounterClear() {
660 break_point_hit_count = 0;
661 exception_hit_count = 0;
662 uncaught_exception_hit_count = 0;
663}
664
665static void DebugEventCounter(v8::DebugEvent event,
666 v8::Handle<v8::Object> exec_state,
667 v8::Handle<v8::Object> event_data,
668 v8::Handle<v8::Value> data) {
669 // When hitting a debug event listener there must be a break set.
670 CHECK_NE(v8::internal::Debug::break_id(), 0);
671
672 // Count the number of breaks.
673 if (event == v8::Break) {
674 break_point_hit_count++;
675 } else if (event == v8::Exception) {
676 exception_hit_count++;
677
678 // Check whether the exception was uncaught.
679 v8::Local<v8::String> fun_name = v8::String::New("uncaught");
680 v8::Local<v8::Function> fun =
681 v8::Function::Cast(*event_data->Get(fun_name));
682 v8::Local<v8::Value> result = *fun->Call(event_data, 0, NULL);
683 if (result->IsTrue()) {
684 uncaught_exception_hit_count++;
685 }
686 }
687
688 // Collect the JavsScript stack height if the function frame_count is
689 // compiled.
690 if (!frame_count.IsEmpty()) {
691 static const int kArgc = 1;
692 v8::Handle<v8::Value> argv[kArgc] = { exec_state };
693 // Using exec_state as receiver is just to have a receiver.
694 v8::Handle<v8::Value> result = frame_count->Call(exec_state, kArgc, argv);
695 last_js_stack_height = result->Int32Value();
696 }
697}
698
699
700// Debug event handler which evaluates a number of expressions when a break
701// point is hit. Each evaluated expression is compared with an expected value.
702// For this debug event handler to work the following two global varaibles
703// must be initialized.
704// checks: An array of expressions and expected results
705// evaluate_check_function: A JavaScript function (see below)
706
707// Structure for holding checks to do.
708struct EvaluateCheck {
709 const char* expr; // An expression to evaluate when a break point is hit.
710 v8::Handle<v8::Value> expected; // The expected result.
711};
712// Array of checks to do.
713struct EvaluateCheck* checks = NULL;
714// Source for The JavaScript function which can do the evaluation when a break
715// point is hit.
716const char* evaluate_check_source =
717 "function evaluate_check(exec_state, expr, expected) {"
718 " return exec_state.frame(0).evaluate(expr).value() === expected;"
719 "}";
720v8::Local<v8::Function> evaluate_check_function;
721
722// The actual debug event described by the longer comment above.
723static void DebugEventEvaluate(v8::DebugEvent event,
724 v8::Handle<v8::Object> exec_state,
725 v8::Handle<v8::Object> event_data,
726 v8::Handle<v8::Value> data) {
727 // When hitting a debug event listener there must be a break set.
728 CHECK_NE(v8::internal::Debug::break_id(), 0);
729
730 if (event == v8::Break) {
731 for (int i = 0; checks[i].expr != NULL; i++) {
732 const int argc = 3;
733 v8::Handle<v8::Value> argv[argc] = { exec_state,
734 v8::String::New(checks[i].expr),
735 checks[i].expected };
736 v8::Handle<v8::Value> result =
737 evaluate_check_function->Call(exec_state, argc, argv);
738 if (!result->IsTrue()) {
739 v8::String::AsciiValue ascii(checks[i].expected->ToString());
740 V8_Fatal(__FILE__, __LINE__, "%s != %s", checks[i].expr, *ascii);
741 }
742 }
743 }
744}
745
746
747// This debug event listener removes a breakpoint in a function
748int debug_event_remove_break_point = 0;
749static void DebugEventRemoveBreakPoint(v8::DebugEvent event,
750 v8::Handle<v8::Object> exec_state,
751 v8::Handle<v8::Object> event_data,
752 v8::Handle<v8::Value> data) {
753 // When hitting a debug event listener there must be a break set.
754 CHECK_NE(v8::internal::Debug::break_id(), 0);
755
756 if (event == v8::Break) {
757 break_point_hit_count++;
758 v8::Handle<v8::Function> fun = v8::Handle<v8::Function>::Cast(data);
759 ClearBreakPoint(debug_event_remove_break_point);
760 }
761}
762
763
764// Debug event handler which counts break points hit and performs a step
765// afterwards.
766StepAction step_action = StepIn; // Step action to perform when stepping.
767static void DebugEventStep(v8::DebugEvent event,
768 v8::Handle<v8::Object> exec_state,
769 v8::Handle<v8::Object> event_data,
770 v8::Handle<v8::Value> data) {
771 // When hitting a debug event listener there must be a break set.
772 CHECK_NE(v8::internal::Debug::break_id(), 0);
773
774 if (event == v8::Break) {
775 break_point_hit_count++;
776 PrepareStep(step_action);
777 }
778}
779
780
781// Debug event handler which counts break points hit and performs a step
782// afterwards. For each call the expected function is checked.
783// For this debug event handler to work the following two global varaibles
784// must be initialized.
785// expected_step_sequence: An array of the expected function call sequence.
786// frame_function_name: A JavaScript function (see below).
787
788// String containing the expected function call sequence. Note: this only works
789// if functions have name length of one.
790const char* expected_step_sequence = NULL;
791
792// The actual debug event described by the longer comment above.
793static void DebugEventStepSequence(v8::DebugEvent event,
794 v8::Handle<v8::Object> exec_state,
795 v8::Handle<v8::Object> event_data,
796 v8::Handle<v8::Value> data) {
797 // When hitting a debug event listener there must be a break set.
798 CHECK_NE(v8::internal::Debug::break_id(), 0);
799
800 if (event == v8::Break || event == v8::Exception) {
801 // Check that the current function is the expected.
802 CHECK(break_point_hit_count <
Steve Blockd0582a62009-12-15 09:54:21 +0000803 StrLength(expected_step_sequence));
Steve Blocka7e24c12009-10-30 11:49:00 +0000804 const int argc = 1;
805 v8::Handle<v8::Value> argv[argc] = { exec_state };
806 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
807 argc, argv);
808 CHECK(result->IsString());
809 v8::String::AsciiValue function_name(result->ToString());
Steve Blockd0582a62009-12-15 09:54:21 +0000810 CHECK_EQ(1, StrLength(*function_name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000811 CHECK_EQ((*function_name)[0],
812 expected_step_sequence[break_point_hit_count]);
813
814 // Perform step.
815 break_point_hit_count++;
816 PrepareStep(step_action);
817 }
818}
819
820
821// Debug event handler which performs a garbage collection.
822static void DebugEventBreakPointCollectGarbage(
823 v8::DebugEvent event,
824 v8::Handle<v8::Object> exec_state,
825 v8::Handle<v8::Object> event_data,
826 v8::Handle<v8::Value> data) {
827 // When hitting a debug event listener there must be a break set.
828 CHECK_NE(v8::internal::Debug::break_id(), 0);
829
830 // Perform a garbage collection when break point is hit and continue. Based
831 // on the number of break points hit either scavenge or mark compact
832 // collector is used.
833 if (event == v8::Break) {
834 break_point_hit_count++;
835 if (break_point_hit_count % 2 == 0) {
836 // Scavenge.
837 Heap::CollectGarbage(0, v8::internal::NEW_SPACE);
838 } else {
839 // Mark sweep (and perhaps compact).
840 Heap::CollectAllGarbage(false);
841 }
842 }
843}
844
845
846// Debug event handler which re-issues a debug break and calls the garbage
847// collector to have the heap verified.
848static void DebugEventBreak(v8::DebugEvent event,
849 v8::Handle<v8::Object> exec_state,
850 v8::Handle<v8::Object> event_data,
851 v8::Handle<v8::Value> data) {
852 // When hitting a debug event listener there must be a break set.
853 CHECK_NE(v8::internal::Debug::break_id(), 0);
854
855 if (event == v8::Break) {
856 // Count the number of breaks.
857 break_point_hit_count++;
858
859 // Run the garbage collector to enforce heap verification if option
860 // --verify-heap is set.
861 Heap::CollectGarbage(0, v8::internal::NEW_SPACE);
862
863 // Set the break flag again to come back here as soon as possible.
864 v8::Debug::DebugBreak();
865 }
866}
867
868
Steve Blockd0582a62009-12-15 09:54:21 +0000869// Debug event handler which re-issues a debug break until a limit has been
870// reached.
871int max_break_point_hit_count = 0;
872static void DebugEventBreakMax(v8::DebugEvent event,
873 v8::Handle<v8::Object> exec_state,
874 v8::Handle<v8::Object> event_data,
875 v8::Handle<v8::Value> data) {
876 // When hitting a debug event listener there must be a break set.
877 CHECK_NE(v8::internal::Debug::break_id(), 0);
878
879 if (event == v8::Break && break_point_hit_count < max_break_point_hit_count) {
880 // Count the number of breaks.
881 break_point_hit_count++;
882
883 // Set the break flag again to come back here as soon as possible.
884 v8::Debug::DebugBreak();
885 }
886}
887
888
Steve Blocka7e24c12009-10-30 11:49:00 +0000889// --- M e s s a g e C a l l b a c k
890
891
892// Message callback which counts the number of messages.
893int message_callback_count = 0;
894
895static void MessageCallbackCountClear() {
896 message_callback_count = 0;
897}
898
899static void MessageCallbackCount(v8::Handle<v8::Message> message,
900 v8::Handle<v8::Value> data) {
901 message_callback_count++;
902}
903
904
905// --- T h e A c t u a l T e s t s
906
907
908// Test that the debug break function is the expected one for different kinds
909// of break locations.
910TEST(DebugStub) {
911 using ::v8::internal::Builtins;
912 v8::HandleScope scope;
913 DebugLocalContext env;
914
915 CheckDebugBreakFunction(&env,
916 "function f1(){}", "f1",
917 0,
918 v8::internal::RelocInfo::JS_RETURN,
919 NULL);
920 CheckDebugBreakFunction(&env,
921 "function f2(){x=1;}", "f2",
922 0,
923 v8::internal::RelocInfo::CODE_TARGET,
924 Builtins::builtin(Builtins::StoreIC_DebugBreak));
925 CheckDebugBreakFunction(&env,
926 "function f3(){var a=x;}", "f3",
927 0,
928 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
929 Builtins::builtin(Builtins::LoadIC_DebugBreak));
930
931// TODO(1240753): Make the test architecture independent or split
932// parts of the debugger into architecture dependent files. This
933// part currently disabled as it is not portable between IA32/ARM.
934// Currently on ICs for keyed store/load on ARM.
935#if !defined (__arm__) && !defined(__thumb__)
936 CheckDebugBreakFunction(
937 &env,
938 "function f4(){var index='propertyName'; var a={}; a[index] = 'x';}",
939 "f4",
940 0,
941 v8::internal::RelocInfo::CODE_TARGET,
942 Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak));
943 CheckDebugBreakFunction(
944 &env,
945 "function f5(){var index='propertyName'; var a={}; return a[index];}",
946 "f5",
947 0,
948 v8::internal::RelocInfo::CODE_TARGET,
949 Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak));
950#endif
951
952 // Check the debug break code stubs for call ICs with different number of
953 // parameters.
954 Handle<Code> debug_break_0 = v8::internal::ComputeCallDebugBreak(0);
955 Handle<Code> debug_break_1 = v8::internal::ComputeCallDebugBreak(1);
956 Handle<Code> debug_break_4 = v8::internal::ComputeCallDebugBreak(4);
957
958 CheckDebugBreakFunction(&env,
959 "function f4_0(){x();}", "f4_0",
960 0,
961 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
962 *debug_break_0);
963
964 CheckDebugBreakFunction(&env,
965 "function f4_1(){x(1);}", "f4_1",
966 0,
967 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
968 *debug_break_1);
969
970 CheckDebugBreakFunction(&env,
971 "function f4_4(){x(1,2,3,4);}", "f4_4",
972 0,
973 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
974 *debug_break_4);
975}
976
977
978// Test that the debug info in the VM is in sync with the functions being
979// debugged.
980TEST(DebugInfo) {
981 v8::HandleScope scope;
982 DebugLocalContext env;
983 // Create a couple of functions for the test.
984 v8::Local<v8::Function> foo =
985 CompileFunction(&env, "function foo(){}", "foo");
986 v8::Local<v8::Function> bar =
987 CompileFunction(&env, "function bar(){}", "bar");
988 // Initially no functions are debugged.
989 CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
990 CHECK(!HasDebugInfo(foo));
991 CHECK(!HasDebugInfo(bar));
992 // One function (foo) is debugged.
993 int bp1 = SetBreakPoint(foo, 0);
994 CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
995 CHECK(HasDebugInfo(foo));
996 CHECK(!HasDebugInfo(bar));
997 // Two functions are debugged.
998 int bp2 = SetBreakPoint(bar, 0);
999 CHECK_EQ(2, v8::internal::GetDebuggedFunctions()->length());
1000 CHECK(HasDebugInfo(foo));
1001 CHECK(HasDebugInfo(bar));
1002 // One function (bar) is debugged.
1003 ClearBreakPoint(bp1);
1004 CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
1005 CHECK(!HasDebugInfo(foo));
1006 CHECK(HasDebugInfo(bar));
1007 // No functions are debugged.
1008 ClearBreakPoint(bp2);
1009 CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
1010 CHECK(!HasDebugInfo(foo));
1011 CHECK(!HasDebugInfo(bar));
1012}
1013
1014
1015// Test that a break point can be set at an IC store location.
1016TEST(BreakPointICStore) {
1017 break_point_hit_count = 0;
1018 v8::HandleScope scope;
1019 DebugLocalContext env;
1020
1021 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1022 v8::Undefined());
1023 v8::Script::Compile(v8::String::New("function foo(){bar=0;}"))->Run();
1024 v8::Local<v8::Function> foo =
1025 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1026
1027 // Run without breakpoints.
1028 foo->Call(env->Global(), 0, NULL);
1029 CHECK_EQ(0, break_point_hit_count);
1030
1031 // Run with breakpoint
1032 int bp = SetBreakPoint(foo, 0);
1033 foo->Call(env->Global(), 0, NULL);
1034 CHECK_EQ(1, break_point_hit_count);
1035 foo->Call(env->Global(), 0, NULL);
1036 CHECK_EQ(2, break_point_hit_count);
1037
1038 // Run without breakpoints.
1039 ClearBreakPoint(bp);
1040 foo->Call(env->Global(), 0, NULL);
1041 CHECK_EQ(2, break_point_hit_count);
1042
1043 v8::Debug::SetDebugEventListener(NULL);
1044 CheckDebuggerUnloaded();
1045}
1046
1047
1048// Test that a break point can be set at an IC load location.
1049TEST(BreakPointICLoad) {
1050 break_point_hit_count = 0;
1051 v8::HandleScope scope;
1052 DebugLocalContext env;
1053 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1054 v8::Undefined());
1055 v8::Script::Compile(v8::String::New("bar=1"))->Run();
1056 v8::Script::Compile(v8::String::New("function foo(){var x=bar;}"))->Run();
1057 v8::Local<v8::Function> foo =
1058 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1059
1060 // Run without breakpoints.
1061 foo->Call(env->Global(), 0, NULL);
1062 CHECK_EQ(0, break_point_hit_count);
1063
1064 // Run with breakpoint
1065 int bp = SetBreakPoint(foo, 0);
1066 foo->Call(env->Global(), 0, NULL);
1067 CHECK_EQ(1, break_point_hit_count);
1068 foo->Call(env->Global(), 0, NULL);
1069 CHECK_EQ(2, break_point_hit_count);
1070
1071 // Run without breakpoints.
1072 ClearBreakPoint(bp);
1073 foo->Call(env->Global(), 0, NULL);
1074 CHECK_EQ(2, break_point_hit_count);
1075
1076 v8::Debug::SetDebugEventListener(NULL);
1077 CheckDebuggerUnloaded();
1078}
1079
1080
1081// Test that a break point can be set at an IC call location.
1082TEST(BreakPointICCall) {
1083 break_point_hit_count = 0;
1084 v8::HandleScope scope;
1085 DebugLocalContext env;
1086 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1087 v8::Undefined());
1088 v8::Script::Compile(v8::String::New("function bar(){}"))->Run();
1089 v8::Script::Compile(v8::String::New("function foo(){bar();}"))->Run();
1090 v8::Local<v8::Function> foo =
1091 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1092
1093 // Run without breakpoints.
1094 foo->Call(env->Global(), 0, NULL);
1095 CHECK_EQ(0, break_point_hit_count);
1096
1097 // Run with breakpoint
1098 int bp = SetBreakPoint(foo, 0);
1099 foo->Call(env->Global(), 0, NULL);
1100 CHECK_EQ(1, break_point_hit_count);
1101 foo->Call(env->Global(), 0, NULL);
1102 CHECK_EQ(2, break_point_hit_count);
1103
1104 // Run without breakpoints.
1105 ClearBreakPoint(bp);
1106 foo->Call(env->Global(), 0, NULL);
1107 CHECK_EQ(2, break_point_hit_count);
1108
1109 v8::Debug::SetDebugEventListener(NULL);
1110 CheckDebuggerUnloaded();
1111}
1112
1113
1114// Test that a break point can be set at a return store location.
1115TEST(BreakPointReturn) {
1116 break_point_hit_count = 0;
1117 v8::HandleScope scope;
1118 DebugLocalContext env;
1119
1120 // Create a functions for checking the source line and column when hitting
1121 // a break point.
1122 frame_source_line = CompileFunction(&env,
1123 frame_source_line_source,
1124 "frame_source_line");
1125 frame_source_column = CompileFunction(&env,
1126 frame_source_column_source,
1127 "frame_source_column");
1128
1129
1130 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1131 v8::Undefined());
1132 v8::Script::Compile(v8::String::New("function foo(){}"))->Run();
1133 v8::Local<v8::Function> foo =
1134 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1135
1136 // Run without breakpoints.
1137 foo->Call(env->Global(), 0, NULL);
1138 CHECK_EQ(0, break_point_hit_count);
1139
1140 // Run with breakpoint
1141 int bp = SetBreakPoint(foo, 0);
1142 foo->Call(env->Global(), 0, NULL);
1143 CHECK_EQ(1, break_point_hit_count);
1144 CHECK_EQ(0, last_source_line);
1145 CHECK_EQ(16, last_source_column);
1146 foo->Call(env->Global(), 0, NULL);
1147 CHECK_EQ(2, break_point_hit_count);
1148 CHECK_EQ(0, last_source_line);
1149 CHECK_EQ(16, last_source_column);
1150
1151 // Run without breakpoints.
1152 ClearBreakPoint(bp);
1153 foo->Call(env->Global(), 0, NULL);
1154 CHECK_EQ(2, break_point_hit_count);
1155
1156 v8::Debug::SetDebugEventListener(NULL);
1157 CheckDebuggerUnloaded();
1158}
1159
1160
1161static void CallWithBreakPoints(v8::Local<v8::Object> recv,
1162 v8::Local<v8::Function> f,
1163 int break_point_count,
1164 int call_count) {
1165 break_point_hit_count = 0;
1166 for (int i = 0; i < call_count; i++) {
1167 f->Call(recv, 0, NULL);
1168 CHECK_EQ((i + 1) * break_point_count, break_point_hit_count);
1169 }
1170}
1171
1172// Test GC during break point processing.
1173TEST(GCDuringBreakPointProcessing) {
1174 break_point_hit_count = 0;
1175 v8::HandleScope scope;
1176 DebugLocalContext env;
1177
1178 v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage,
1179 v8::Undefined());
1180 v8::Local<v8::Function> foo;
1181
1182 // Test IC store break point with garbage collection.
1183 foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1184 SetBreakPoint(foo, 0);
1185 CallWithBreakPoints(env->Global(), foo, 1, 10);
1186
1187 // Test IC load break point with garbage collection.
1188 foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1189 SetBreakPoint(foo, 0);
1190 CallWithBreakPoints(env->Global(), foo, 1, 10);
1191
1192 // Test IC call break point with garbage collection.
1193 foo = CompileFunction(&env, "function bar(){};function foo(){bar();}", "foo");
1194 SetBreakPoint(foo, 0);
1195 CallWithBreakPoints(env->Global(), foo, 1, 10);
1196
1197 // Test return break point with garbage collection.
1198 foo = CompileFunction(&env, "function foo(){}", "foo");
1199 SetBreakPoint(foo, 0);
1200 CallWithBreakPoints(env->Global(), foo, 1, 25);
1201
1202 v8::Debug::SetDebugEventListener(NULL);
1203 CheckDebuggerUnloaded();
1204}
1205
1206
1207// Call the function three times with different garbage collections in between
1208// and make sure that the break point survives.
1209static void CallAndGC(v8::Local<v8::Object> recv, v8::Local<v8::Function> f) {
1210 break_point_hit_count = 0;
1211
1212 for (int i = 0; i < 3; i++) {
1213 // Call function.
1214 f->Call(recv, 0, NULL);
1215 CHECK_EQ(1 + i * 3, break_point_hit_count);
1216
1217 // Scavenge and call function.
1218 Heap::CollectGarbage(0, v8::internal::NEW_SPACE);
1219 f->Call(recv, 0, NULL);
1220 CHECK_EQ(2 + i * 3, break_point_hit_count);
1221
1222 // Mark sweep (and perhaps compact) and call function.
1223 Heap::CollectAllGarbage(false);
1224 f->Call(recv, 0, NULL);
1225 CHECK_EQ(3 + i * 3, break_point_hit_count);
1226 }
1227}
1228
1229
1230// Test that a break point can be set at a return store location.
1231TEST(BreakPointSurviveGC) {
1232 break_point_hit_count = 0;
1233 v8::HandleScope scope;
1234 DebugLocalContext env;
1235
1236 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1237 v8::Undefined());
1238 v8::Local<v8::Function> foo;
1239
1240 // Test IC store break point with garbage collection.
1241 foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1242 SetBreakPoint(foo, 0);
1243 CallAndGC(env->Global(), foo);
1244
1245 // Test IC load break point with garbage collection.
1246 foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1247 SetBreakPoint(foo, 0);
1248 CallAndGC(env->Global(), foo);
1249
1250 // Test IC call break point with garbage collection.
1251 foo = CompileFunction(&env, "function bar(){};function foo(){bar();}", "foo");
1252 SetBreakPoint(foo, 0);
1253 CallAndGC(env->Global(), foo);
1254
1255 // Test return break point with garbage collection.
1256 foo = CompileFunction(&env, "function foo(){}", "foo");
1257 SetBreakPoint(foo, 0);
1258 CallAndGC(env->Global(), foo);
1259
1260 v8::Debug::SetDebugEventListener(NULL);
1261 CheckDebuggerUnloaded();
1262}
1263
1264
1265// Test that break points can be set using the global Debug object.
1266TEST(BreakPointThroughJavaScript) {
1267 break_point_hit_count = 0;
1268 v8::HandleScope scope;
1269 DebugLocalContext env;
1270 env.ExposeDebug();
1271
1272 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1273 v8::Undefined());
1274 v8::Script::Compile(v8::String::New("function bar(){}"))->Run();
1275 v8::Script::Compile(v8::String::New("function foo(){bar();bar();}"))->Run();
1276 // 012345678901234567890
1277 // 1 2
1278 // Break points are set at position 3 and 9
1279 v8::Local<v8::Script> foo = v8::Script::Compile(v8::String::New("foo()"));
1280
1281 // Run without breakpoints.
1282 foo->Run();
1283 CHECK_EQ(0, break_point_hit_count);
1284
1285 // Run with one breakpoint
1286 int bp1 = SetBreakPointFromJS("foo", 0, 3);
1287 foo->Run();
1288 CHECK_EQ(1, break_point_hit_count);
1289 foo->Run();
1290 CHECK_EQ(2, break_point_hit_count);
1291
1292 // Run with two breakpoints
1293 int bp2 = SetBreakPointFromJS("foo", 0, 9);
1294 foo->Run();
1295 CHECK_EQ(4, break_point_hit_count);
1296 foo->Run();
1297 CHECK_EQ(6, break_point_hit_count);
1298
1299 // Run with one breakpoint
1300 ClearBreakPointFromJS(bp2);
1301 foo->Run();
1302 CHECK_EQ(7, break_point_hit_count);
1303 foo->Run();
1304 CHECK_EQ(8, break_point_hit_count);
1305
1306 // Run without breakpoints.
1307 ClearBreakPointFromJS(bp1);
1308 foo->Run();
1309 CHECK_EQ(8, break_point_hit_count);
1310
1311 v8::Debug::SetDebugEventListener(NULL);
1312 CheckDebuggerUnloaded();
1313
1314 // Make sure that the break point numbers are consecutive.
1315 CHECK_EQ(1, bp1);
1316 CHECK_EQ(2, bp2);
1317}
1318
1319
1320// Test that break points on scripts identified by name can be set using the
1321// global Debug object.
1322TEST(ScriptBreakPointByNameThroughJavaScript) {
1323 break_point_hit_count = 0;
1324 v8::HandleScope scope;
1325 DebugLocalContext env;
1326 env.ExposeDebug();
1327
1328 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1329 v8::Undefined());
1330
1331 v8::Local<v8::String> script = v8::String::New(
1332 "function f() {\n"
1333 " function h() {\n"
1334 " a = 0; // line 2\n"
1335 " }\n"
1336 " b = 1; // line 4\n"
1337 " return h();\n"
1338 "}\n"
1339 "\n"
1340 "function g() {\n"
1341 " function h() {\n"
1342 " a = 0;\n"
1343 " }\n"
1344 " b = 2; // line 12\n"
1345 " h();\n"
1346 " b = 3; // line 14\n"
1347 " f(); // line 15\n"
1348 "}");
1349
1350 // Compile the script and get the two functions.
1351 v8::ScriptOrigin origin =
1352 v8::ScriptOrigin(v8::String::New("test"));
1353 v8::Script::Compile(script, &origin)->Run();
1354 v8::Local<v8::Function> f =
1355 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1356 v8::Local<v8::Function> g =
1357 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
1358
1359 // Call f and g without break points.
1360 break_point_hit_count = 0;
1361 f->Call(env->Global(), 0, NULL);
1362 CHECK_EQ(0, break_point_hit_count);
1363 g->Call(env->Global(), 0, NULL);
1364 CHECK_EQ(0, break_point_hit_count);
1365
1366 // Call f and g with break point on line 12.
1367 int sbp1 = SetScriptBreakPointByNameFromJS("test", 12, 0);
1368 break_point_hit_count = 0;
1369 f->Call(env->Global(), 0, NULL);
1370 CHECK_EQ(0, break_point_hit_count);
1371 g->Call(env->Global(), 0, NULL);
1372 CHECK_EQ(1, break_point_hit_count);
1373
1374 // Remove the break point again.
1375 break_point_hit_count = 0;
1376 ClearBreakPointFromJS(sbp1);
1377 f->Call(env->Global(), 0, NULL);
1378 CHECK_EQ(0, break_point_hit_count);
1379 g->Call(env->Global(), 0, NULL);
1380 CHECK_EQ(0, break_point_hit_count);
1381
1382 // Call f and g with break point on line 2.
1383 int sbp2 = SetScriptBreakPointByNameFromJS("test", 2, 0);
1384 break_point_hit_count = 0;
1385 f->Call(env->Global(), 0, NULL);
1386 CHECK_EQ(1, break_point_hit_count);
1387 g->Call(env->Global(), 0, NULL);
1388 CHECK_EQ(2, break_point_hit_count);
1389
1390 // Call f and g with break point on line 2, 4, 12, 14 and 15.
1391 int sbp3 = SetScriptBreakPointByNameFromJS("test", 4, 0);
1392 int sbp4 = SetScriptBreakPointByNameFromJS("test", 12, 0);
1393 int sbp5 = SetScriptBreakPointByNameFromJS("test", 14, 0);
1394 int sbp6 = SetScriptBreakPointByNameFromJS("test", 15, 0);
1395 break_point_hit_count = 0;
1396 f->Call(env->Global(), 0, NULL);
1397 CHECK_EQ(2, break_point_hit_count);
1398 g->Call(env->Global(), 0, NULL);
1399 CHECK_EQ(7, break_point_hit_count);
1400
1401 // Remove all the break points again.
1402 break_point_hit_count = 0;
1403 ClearBreakPointFromJS(sbp2);
1404 ClearBreakPointFromJS(sbp3);
1405 ClearBreakPointFromJS(sbp4);
1406 ClearBreakPointFromJS(sbp5);
1407 ClearBreakPointFromJS(sbp6);
1408 f->Call(env->Global(), 0, NULL);
1409 CHECK_EQ(0, break_point_hit_count);
1410 g->Call(env->Global(), 0, NULL);
1411 CHECK_EQ(0, break_point_hit_count);
1412
1413 v8::Debug::SetDebugEventListener(NULL);
1414 CheckDebuggerUnloaded();
1415
1416 // Make sure that the break point numbers are consecutive.
1417 CHECK_EQ(1, sbp1);
1418 CHECK_EQ(2, sbp2);
1419 CHECK_EQ(3, sbp3);
1420 CHECK_EQ(4, sbp4);
1421 CHECK_EQ(5, sbp5);
1422 CHECK_EQ(6, sbp6);
1423}
1424
1425
1426TEST(ScriptBreakPointByIdThroughJavaScript) {
1427 break_point_hit_count = 0;
1428 v8::HandleScope scope;
1429 DebugLocalContext env;
1430 env.ExposeDebug();
1431
1432 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1433 v8::Undefined());
1434
1435 v8::Local<v8::String> source = v8::String::New(
1436 "function f() {\n"
1437 " function h() {\n"
1438 " a = 0; // line 2\n"
1439 " }\n"
1440 " b = 1; // line 4\n"
1441 " return h();\n"
1442 "}\n"
1443 "\n"
1444 "function g() {\n"
1445 " function h() {\n"
1446 " a = 0;\n"
1447 " }\n"
1448 " b = 2; // line 12\n"
1449 " h();\n"
1450 " b = 3; // line 14\n"
1451 " f(); // line 15\n"
1452 "}");
1453
1454 // Compile the script and get the two functions.
1455 v8::ScriptOrigin origin =
1456 v8::ScriptOrigin(v8::String::New("test"));
1457 v8::Local<v8::Script> script = v8::Script::Compile(source, &origin);
1458 script->Run();
1459 v8::Local<v8::Function> f =
1460 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1461 v8::Local<v8::Function> g =
1462 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
1463
1464 // Get the script id knowing that internally it is a 32 integer.
1465 uint32_t script_id = script->Id()->Uint32Value();
1466
1467 // Call f and g without break points.
1468 break_point_hit_count = 0;
1469 f->Call(env->Global(), 0, NULL);
1470 CHECK_EQ(0, break_point_hit_count);
1471 g->Call(env->Global(), 0, NULL);
1472 CHECK_EQ(0, break_point_hit_count);
1473
1474 // Call f and g with break point on line 12.
1475 int sbp1 = SetScriptBreakPointByIdFromJS(script_id, 12, 0);
1476 break_point_hit_count = 0;
1477 f->Call(env->Global(), 0, NULL);
1478 CHECK_EQ(0, break_point_hit_count);
1479 g->Call(env->Global(), 0, NULL);
1480 CHECK_EQ(1, break_point_hit_count);
1481
1482 // Remove the break point again.
1483 break_point_hit_count = 0;
1484 ClearBreakPointFromJS(sbp1);
1485 f->Call(env->Global(), 0, NULL);
1486 CHECK_EQ(0, break_point_hit_count);
1487 g->Call(env->Global(), 0, NULL);
1488 CHECK_EQ(0, break_point_hit_count);
1489
1490 // Call f and g with break point on line 2.
1491 int sbp2 = SetScriptBreakPointByIdFromJS(script_id, 2, 0);
1492 break_point_hit_count = 0;
1493 f->Call(env->Global(), 0, NULL);
1494 CHECK_EQ(1, break_point_hit_count);
1495 g->Call(env->Global(), 0, NULL);
1496 CHECK_EQ(2, break_point_hit_count);
1497
1498 // Call f and g with break point on line 2, 4, 12, 14 and 15.
1499 int sbp3 = SetScriptBreakPointByIdFromJS(script_id, 4, 0);
1500 int sbp4 = SetScriptBreakPointByIdFromJS(script_id, 12, 0);
1501 int sbp5 = SetScriptBreakPointByIdFromJS(script_id, 14, 0);
1502 int sbp6 = SetScriptBreakPointByIdFromJS(script_id, 15, 0);
1503 break_point_hit_count = 0;
1504 f->Call(env->Global(), 0, NULL);
1505 CHECK_EQ(2, break_point_hit_count);
1506 g->Call(env->Global(), 0, NULL);
1507 CHECK_EQ(7, break_point_hit_count);
1508
1509 // Remove all the break points again.
1510 break_point_hit_count = 0;
1511 ClearBreakPointFromJS(sbp2);
1512 ClearBreakPointFromJS(sbp3);
1513 ClearBreakPointFromJS(sbp4);
1514 ClearBreakPointFromJS(sbp5);
1515 ClearBreakPointFromJS(sbp6);
1516 f->Call(env->Global(), 0, NULL);
1517 CHECK_EQ(0, break_point_hit_count);
1518 g->Call(env->Global(), 0, NULL);
1519 CHECK_EQ(0, break_point_hit_count);
1520
1521 v8::Debug::SetDebugEventListener(NULL);
1522 CheckDebuggerUnloaded();
1523
1524 // Make sure that the break point numbers are consecutive.
1525 CHECK_EQ(1, sbp1);
1526 CHECK_EQ(2, sbp2);
1527 CHECK_EQ(3, sbp3);
1528 CHECK_EQ(4, sbp4);
1529 CHECK_EQ(5, sbp5);
1530 CHECK_EQ(6, sbp6);
1531}
1532
1533
1534// Test conditional script break points.
1535TEST(EnableDisableScriptBreakPoint) {
1536 break_point_hit_count = 0;
1537 v8::HandleScope scope;
1538 DebugLocalContext env;
1539 env.ExposeDebug();
1540
1541 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1542 v8::Undefined());
1543
1544 v8::Local<v8::String> script = v8::String::New(
1545 "function f() {\n"
1546 " a = 0; // line 1\n"
1547 "};");
1548
1549 // Compile the script and get function f.
1550 v8::ScriptOrigin origin =
1551 v8::ScriptOrigin(v8::String::New("test"));
1552 v8::Script::Compile(script, &origin)->Run();
1553 v8::Local<v8::Function> f =
1554 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1555
1556 // Set script break point on line 1 (in function f).
1557 int sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
1558
1559 // Call f while enabeling and disabling the script break point.
1560 break_point_hit_count = 0;
1561 f->Call(env->Global(), 0, NULL);
1562 CHECK_EQ(1, break_point_hit_count);
1563
1564 DisableScriptBreakPointFromJS(sbp);
1565 f->Call(env->Global(), 0, NULL);
1566 CHECK_EQ(1, break_point_hit_count);
1567
1568 EnableScriptBreakPointFromJS(sbp);
1569 f->Call(env->Global(), 0, NULL);
1570 CHECK_EQ(2, break_point_hit_count);
1571
1572 DisableScriptBreakPointFromJS(sbp);
1573 f->Call(env->Global(), 0, NULL);
1574 CHECK_EQ(2, break_point_hit_count);
1575
1576 // Reload the script and get f again checking that the disabeling survives.
1577 v8::Script::Compile(script, &origin)->Run();
1578 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1579 f->Call(env->Global(), 0, NULL);
1580 CHECK_EQ(2, break_point_hit_count);
1581
1582 EnableScriptBreakPointFromJS(sbp);
1583 f->Call(env->Global(), 0, NULL);
1584 CHECK_EQ(3, break_point_hit_count);
1585
1586 v8::Debug::SetDebugEventListener(NULL);
1587 CheckDebuggerUnloaded();
1588}
1589
1590
1591// Test conditional script break points.
1592TEST(ConditionalScriptBreakPoint) {
1593 break_point_hit_count = 0;
1594 v8::HandleScope scope;
1595 DebugLocalContext env;
1596 env.ExposeDebug();
1597
1598 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1599 v8::Undefined());
1600
1601 v8::Local<v8::String> script = v8::String::New(
1602 "count = 0;\n"
1603 "function f() {\n"
1604 " g(count++); // line 2\n"
1605 "};\n"
1606 "function g(x) {\n"
1607 " var a=x; // line 5\n"
1608 "};");
1609
1610 // Compile the script and get function f.
1611 v8::ScriptOrigin origin =
1612 v8::ScriptOrigin(v8::String::New("test"));
1613 v8::Script::Compile(script, &origin)->Run();
1614 v8::Local<v8::Function> f =
1615 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1616
1617 // Set script break point on line 5 (in function g).
1618 int sbp1 = SetScriptBreakPointByNameFromJS("test", 5, 0);
1619
1620 // Call f with different conditions on the script break point.
1621 break_point_hit_count = 0;
1622 ChangeScriptBreakPointConditionFromJS(sbp1, "false");
1623 f->Call(env->Global(), 0, NULL);
1624 CHECK_EQ(0, break_point_hit_count);
1625
1626 ChangeScriptBreakPointConditionFromJS(sbp1, "true");
1627 break_point_hit_count = 0;
1628 f->Call(env->Global(), 0, NULL);
1629 CHECK_EQ(1, break_point_hit_count);
1630
1631 ChangeScriptBreakPointConditionFromJS(sbp1, "a % 2 == 0");
1632 break_point_hit_count = 0;
1633 for (int i = 0; i < 10; i++) {
1634 f->Call(env->Global(), 0, NULL);
1635 }
1636 CHECK_EQ(5, break_point_hit_count);
1637
1638 // Reload the script and get f again checking that the condition survives.
1639 v8::Script::Compile(script, &origin)->Run();
1640 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1641
1642 break_point_hit_count = 0;
1643 for (int i = 0; i < 10; i++) {
1644 f->Call(env->Global(), 0, NULL);
1645 }
1646 CHECK_EQ(5, break_point_hit_count);
1647
1648 v8::Debug::SetDebugEventListener(NULL);
1649 CheckDebuggerUnloaded();
1650}
1651
1652
1653// Test ignore count on script break points.
1654TEST(ScriptBreakPointIgnoreCount) {
1655 break_point_hit_count = 0;
1656 v8::HandleScope scope;
1657 DebugLocalContext env;
1658 env.ExposeDebug();
1659
1660 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1661 v8::Undefined());
1662
1663 v8::Local<v8::String> script = v8::String::New(
1664 "function f() {\n"
1665 " a = 0; // line 1\n"
1666 "};");
1667
1668 // Compile the script and get function f.
1669 v8::ScriptOrigin origin =
1670 v8::ScriptOrigin(v8::String::New("test"));
1671 v8::Script::Compile(script, &origin)->Run();
1672 v8::Local<v8::Function> f =
1673 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1674
1675 // Set script break point on line 1 (in function f).
1676 int sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
1677
1678 // Call f with different ignores on the script break point.
1679 break_point_hit_count = 0;
1680 ChangeScriptBreakPointIgnoreCountFromJS(sbp, 1);
1681 f->Call(env->Global(), 0, NULL);
1682 CHECK_EQ(0, break_point_hit_count);
1683 f->Call(env->Global(), 0, NULL);
1684 CHECK_EQ(1, break_point_hit_count);
1685
1686 ChangeScriptBreakPointIgnoreCountFromJS(sbp, 5);
1687 break_point_hit_count = 0;
1688 for (int i = 0; i < 10; i++) {
1689 f->Call(env->Global(), 0, NULL);
1690 }
1691 CHECK_EQ(5, break_point_hit_count);
1692
1693 // Reload the script and get f again checking that the ignore survives.
1694 v8::Script::Compile(script, &origin)->Run();
1695 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1696
1697 break_point_hit_count = 0;
1698 for (int i = 0; i < 10; i++) {
1699 f->Call(env->Global(), 0, NULL);
1700 }
1701 CHECK_EQ(5, break_point_hit_count);
1702
1703 v8::Debug::SetDebugEventListener(NULL);
1704 CheckDebuggerUnloaded();
1705}
1706
1707
1708// Test that script break points survive when a script is reloaded.
1709TEST(ScriptBreakPointReload) {
1710 break_point_hit_count = 0;
1711 v8::HandleScope scope;
1712 DebugLocalContext env;
1713 env.ExposeDebug();
1714
1715 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1716 v8::Undefined());
1717
1718 v8::Local<v8::Function> f;
1719 v8::Local<v8::String> script = v8::String::New(
1720 "function f() {\n"
1721 " function h() {\n"
1722 " a = 0; // line 2\n"
1723 " }\n"
1724 " b = 1; // line 4\n"
1725 " return h();\n"
1726 "}");
1727
1728 v8::ScriptOrigin origin_1 = v8::ScriptOrigin(v8::String::New("1"));
1729 v8::ScriptOrigin origin_2 = v8::ScriptOrigin(v8::String::New("2"));
1730
1731 // Set a script break point before the script is loaded.
1732 SetScriptBreakPointByNameFromJS("1", 2, 0);
1733
1734 // Compile the script and get the function.
1735 v8::Script::Compile(script, &origin_1)->Run();
1736 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1737
1738 // Call f and check that the script break point is active.
1739 break_point_hit_count = 0;
1740 f->Call(env->Global(), 0, NULL);
1741 CHECK_EQ(1, break_point_hit_count);
1742
1743 // Compile the script again with a different script data and get the
1744 // function.
1745 v8::Script::Compile(script, &origin_2)->Run();
1746 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1747
1748 // Call f and check that no break points are set.
1749 break_point_hit_count = 0;
1750 f->Call(env->Global(), 0, NULL);
1751 CHECK_EQ(0, break_point_hit_count);
1752
1753 // Compile the script again and get the function.
1754 v8::Script::Compile(script, &origin_1)->Run();
1755 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1756
1757 // Call f and check that the script break point is active.
1758 break_point_hit_count = 0;
1759 f->Call(env->Global(), 0, NULL);
1760 CHECK_EQ(1, break_point_hit_count);
1761
1762 v8::Debug::SetDebugEventListener(NULL);
1763 CheckDebuggerUnloaded();
1764}
1765
1766
1767// Test when several scripts has the same script data
1768TEST(ScriptBreakPointMultiple) {
1769 break_point_hit_count = 0;
1770 v8::HandleScope scope;
1771 DebugLocalContext env;
1772 env.ExposeDebug();
1773
1774 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1775 v8::Undefined());
1776
1777 v8::Local<v8::Function> f;
1778 v8::Local<v8::String> script_f = v8::String::New(
1779 "function f() {\n"
1780 " a = 0; // line 1\n"
1781 "}");
1782
1783 v8::Local<v8::Function> g;
1784 v8::Local<v8::String> script_g = v8::String::New(
1785 "function g() {\n"
1786 " b = 0; // line 1\n"
1787 "}");
1788
1789 v8::ScriptOrigin origin =
1790 v8::ScriptOrigin(v8::String::New("test"));
1791
1792 // Set a script break point before the scripts are loaded.
1793 int sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
1794
1795 // Compile the scripts with same script data and get the functions.
1796 v8::Script::Compile(script_f, &origin)->Run();
1797 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1798 v8::Script::Compile(script_g, &origin)->Run();
1799 g = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
1800
1801 // Call f and g and check that the script break point is active.
1802 break_point_hit_count = 0;
1803 f->Call(env->Global(), 0, NULL);
1804 CHECK_EQ(1, break_point_hit_count);
1805 g->Call(env->Global(), 0, NULL);
1806 CHECK_EQ(2, break_point_hit_count);
1807
1808 // Clear the script break point.
1809 ClearBreakPointFromJS(sbp);
1810
1811 // Call f and g and check that the script break point is no longer active.
1812 break_point_hit_count = 0;
1813 f->Call(env->Global(), 0, NULL);
1814 CHECK_EQ(0, break_point_hit_count);
1815 g->Call(env->Global(), 0, NULL);
1816 CHECK_EQ(0, break_point_hit_count);
1817
1818 // Set script break point with the scripts loaded.
1819 sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
1820
1821 // Call f and g and check that the script break point is active.
1822 break_point_hit_count = 0;
1823 f->Call(env->Global(), 0, NULL);
1824 CHECK_EQ(1, break_point_hit_count);
1825 g->Call(env->Global(), 0, NULL);
1826 CHECK_EQ(2, break_point_hit_count);
1827
1828 v8::Debug::SetDebugEventListener(NULL);
1829 CheckDebuggerUnloaded();
1830}
1831
1832
1833// Test the script origin which has both name and line offset.
1834TEST(ScriptBreakPointLineOffset) {
1835 break_point_hit_count = 0;
1836 v8::HandleScope scope;
1837 DebugLocalContext env;
1838 env.ExposeDebug();
1839
1840 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1841 v8::Undefined());
1842
1843 v8::Local<v8::Function> f;
1844 v8::Local<v8::String> script = v8::String::New(
1845 "function f() {\n"
1846 " a = 0; // line 8 as this script has line offset 7\n"
1847 " b = 0; // line 9 as this script has line offset 7\n"
1848 "}");
1849
1850 // Create script origin both name and line offset.
1851 v8::ScriptOrigin origin(v8::String::New("test.html"),
1852 v8::Integer::New(7));
1853
1854 // Set two script break points before the script is loaded.
1855 int sbp1 = SetScriptBreakPointByNameFromJS("test.html", 8, 0);
1856 int sbp2 = SetScriptBreakPointByNameFromJS("test.html", 9, 0);
1857
1858 // Compile the script and get the function.
1859 v8::Script::Compile(script, &origin)->Run();
1860 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1861
1862 // Call f and check that the script break point is active.
1863 break_point_hit_count = 0;
1864 f->Call(env->Global(), 0, NULL);
1865 CHECK_EQ(2, break_point_hit_count);
1866
1867 // Clear the script break points.
1868 ClearBreakPointFromJS(sbp1);
1869 ClearBreakPointFromJS(sbp2);
1870
1871 // Call f and check that no script break points are active.
1872 break_point_hit_count = 0;
1873 f->Call(env->Global(), 0, NULL);
1874 CHECK_EQ(0, break_point_hit_count);
1875
1876 // Set a script break point with the script loaded.
1877 sbp1 = SetScriptBreakPointByNameFromJS("test.html", 9, 0);
1878
1879 // Call f and check that the script break point is active.
1880 break_point_hit_count = 0;
1881 f->Call(env->Global(), 0, NULL);
1882 CHECK_EQ(1, break_point_hit_count);
1883
1884 v8::Debug::SetDebugEventListener(NULL);
1885 CheckDebuggerUnloaded();
1886}
1887
1888
1889// Test script break points set on lines.
1890TEST(ScriptBreakPointLine) {
1891 v8::HandleScope scope;
1892 DebugLocalContext env;
1893 env.ExposeDebug();
1894
1895 // Create a function for checking the function when hitting a break point.
1896 frame_function_name = CompileFunction(&env,
1897 frame_function_name_source,
1898 "frame_function_name");
1899
1900 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1901 v8::Undefined());
1902
1903 v8::Local<v8::Function> f;
1904 v8::Local<v8::Function> g;
1905 v8::Local<v8::String> script = v8::String::New(
1906 "a = 0 // line 0\n"
1907 "function f() {\n"
1908 " a = 1; // line 2\n"
1909 "}\n"
1910 " a = 2; // line 4\n"
1911 " /* xx */ function g() { // line 5\n"
1912 " function h() { // line 6\n"
1913 " a = 3; // line 7\n"
1914 " }\n"
1915 " h(); // line 9\n"
1916 " a = 4; // line 10\n"
1917 " }\n"
1918 " a=5; // line 12");
1919
1920 // Set a couple script break point before the script is loaded.
1921 int sbp1 = SetScriptBreakPointByNameFromJS("test.html", 0, -1);
1922 int sbp2 = SetScriptBreakPointByNameFromJS("test.html", 1, -1);
1923 int sbp3 = SetScriptBreakPointByNameFromJS("test.html", 5, -1);
1924
1925 // Compile the script and get the function.
1926 break_point_hit_count = 0;
1927 v8::ScriptOrigin origin(v8::String::New("test.html"), v8::Integer::New(0));
1928 v8::Script::Compile(script, &origin)->Run();
1929 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1930 g = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
1931
1932 // Chesk that a break point was hit when the script was run.
1933 CHECK_EQ(1, break_point_hit_count);
Steve Blockd0582a62009-12-15 09:54:21 +00001934 CHECK_EQ(0, StrLength(last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00001935
1936 // Call f and check that the script break point.
1937 f->Call(env->Global(), 0, NULL);
1938 CHECK_EQ(2, break_point_hit_count);
1939 CHECK_EQ("f", last_function_hit);
1940
1941 // Call g and check that the script break point.
1942 g->Call(env->Global(), 0, NULL);
1943 CHECK_EQ(3, break_point_hit_count);
1944 CHECK_EQ("g", last_function_hit);
1945
1946 // Clear the script break point on g and set one on h.
1947 ClearBreakPointFromJS(sbp3);
1948 int sbp4 = SetScriptBreakPointByNameFromJS("test.html", 6, -1);
1949
1950 // Call g and check that the script break point in h is hit.
1951 g->Call(env->Global(), 0, NULL);
1952 CHECK_EQ(4, break_point_hit_count);
1953 CHECK_EQ("h", last_function_hit);
1954
1955 // Clear break points in f and h. Set a new one in the script between
1956 // functions f and g and test that there is no break points in f and g any
1957 // more.
1958 ClearBreakPointFromJS(sbp2);
1959 ClearBreakPointFromJS(sbp4);
1960 int sbp5 = SetScriptBreakPointByNameFromJS("test.html", 4, -1);
1961 break_point_hit_count = 0;
1962 f->Call(env->Global(), 0, NULL);
1963 g->Call(env->Global(), 0, NULL);
1964 CHECK_EQ(0, break_point_hit_count);
1965
1966 // Reload the script which should hit two break points.
1967 break_point_hit_count = 0;
1968 v8::Script::Compile(script, &origin)->Run();
1969 CHECK_EQ(2, break_point_hit_count);
Steve Blockd0582a62009-12-15 09:54:21 +00001970 CHECK_EQ(0, StrLength(last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00001971
1972 // Set a break point in the code after the last function decleration.
1973 int sbp6 = SetScriptBreakPointByNameFromJS("test.html", 12, -1);
1974
1975 // Reload the script which should hit three break points.
1976 break_point_hit_count = 0;
1977 v8::Script::Compile(script, &origin)->Run();
1978 CHECK_EQ(3, break_point_hit_count);
Steve Blockd0582a62009-12-15 09:54:21 +00001979 CHECK_EQ(0, StrLength(last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00001980
1981 // Clear the last break points, and reload the script which should not hit any
1982 // break points.
1983 ClearBreakPointFromJS(sbp1);
1984 ClearBreakPointFromJS(sbp5);
1985 ClearBreakPointFromJS(sbp6);
1986 break_point_hit_count = 0;
1987 v8::Script::Compile(script, &origin)->Run();
1988 CHECK_EQ(0, break_point_hit_count);
1989
1990 v8::Debug::SetDebugEventListener(NULL);
1991 CheckDebuggerUnloaded();
1992}
1993
1994
1995// Test that it is possible to remove the last break point for a function
1996// inside the break handling of that break point.
1997TEST(RemoveBreakPointInBreak) {
1998 v8::HandleScope scope;
1999 DebugLocalContext env;
2000
2001 v8::Local<v8::Function> foo =
2002 CompileFunction(&env, "function foo(){a=1;}", "foo");
2003 debug_event_remove_break_point = SetBreakPoint(foo, 0);
2004
2005 // Register the debug event listener pasing the function
2006 v8::Debug::SetDebugEventListener(DebugEventRemoveBreakPoint, foo);
2007
2008 break_point_hit_count = 0;
2009 foo->Call(env->Global(), 0, NULL);
2010 CHECK_EQ(1, break_point_hit_count);
2011
2012 break_point_hit_count = 0;
2013 foo->Call(env->Global(), 0, NULL);
2014 CHECK_EQ(0, break_point_hit_count);
2015
2016 v8::Debug::SetDebugEventListener(NULL);
2017 CheckDebuggerUnloaded();
2018}
2019
2020
2021// Test that the debugger statement causes a break.
2022TEST(DebuggerStatement) {
2023 break_point_hit_count = 0;
2024 v8::HandleScope scope;
2025 DebugLocalContext env;
2026 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2027 v8::Undefined());
2028 v8::Script::Compile(v8::String::New("function bar(){debugger}"))->Run();
2029 v8::Script::Compile(v8::String::New(
2030 "function foo(){debugger;debugger;}"))->Run();
2031 v8::Local<v8::Function> foo =
2032 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
2033 v8::Local<v8::Function> bar =
2034 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("bar")));
2035
2036 // Run function with debugger statement
2037 bar->Call(env->Global(), 0, NULL);
2038 CHECK_EQ(1, break_point_hit_count);
2039
2040 // Run function with two debugger statement
2041 foo->Call(env->Global(), 0, NULL);
2042 CHECK_EQ(3, break_point_hit_count);
2043
2044 v8::Debug::SetDebugEventListener(NULL);
2045 CheckDebuggerUnloaded();
2046}
2047
2048
2049// Thest that the evaluation of expressions when a break point is hit generates
2050// the correct results.
2051TEST(DebugEvaluate) {
2052 v8::HandleScope scope;
2053 DebugLocalContext env;
2054 env.ExposeDebug();
2055
2056 // Create a function for checking the evaluation when hitting a break point.
2057 evaluate_check_function = CompileFunction(&env,
2058 evaluate_check_source,
2059 "evaluate_check");
2060 // Register the debug event listener
2061 v8::Debug::SetDebugEventListener(DebugEventEvaluate);
2062
2063 // Different expected vaules of x and a when in a break point (u = undefined,
2064 // d = Hello, world!).
2065 struct EvaluateCheck checks_uu[] = {
2066 {"x", v8::Undefined()},
2067 {"a", v8::Undefined()},
2068 {NULL, v8::Handle<v8::Value>()}
2069 };
2070 struct EvaluateCheck checks_hu[] = {
2071 {"x", v8::String::New("Hello, world!")},
2072 {"a", v8::Undefined()},
2073 {NULL, v8::Handle<v8::Value>()}
2074 };
2075 struct EvaluateCheck checks_hh[] = {
2076 {"x", v8::String::New("Hello, world!")},
2077 {"a", v8::String::New("Hello, world!")},
2078 {NULL, v8::Handle<v8::Value>()}
2079 };
2080
2081 // Simple test function. The "y=0" is in the function foo to provide a break
2082 // location. For "y=0" the "y" is at position 15 in the barbar function
2083 // therefore setting breakpoint at position 15 will break at "y=0" and
2084 // setting it higher will break after.
2085 v8::Local<v8::Function> foo = CompileFunction(&env,
2086 "function foo(x) {"
2087 " var a;"
2088 " y=0; /* To ensure break location.*/"
2089 " a=x;"
2090 "}",
2091 "foo");
2092 const int foo_break_position = 15;
2093
2094 // Arguments with one parameter "Hello, world!"
2095 v8::Handle<v8::Value> argv_foo[1] = { v8::String::New("Hello, world!") };
2096
2097 // Call foo with breakpoint set before a=x and undefined as parameter.
2098 int bp = SetBreakPoint(foo, foo_break_position);
2099 checks = checks_uu;
2100 foo->Call(env->Global(), 0, NULL);
2101
2102 // Call foo with breakpoint set before a=x and parameter "Hello, world!".
2103 checks = checks_hu;
2104 foo->Call(env->Global(), 1, argv_foo);
2105
2106 // Call foo with breakpoint set after a=x and parameter "Hello, world!".
2107 ClearBreakPoint(bp);
2108 SetBreakPoint(foo, foo_break_position + 1);
2109 checks = checks_hh;
2110 foo->Call(env->Global(), 1, argv_foo);
2111
2112 // Test function with an inner function. The "y=0" is in function barbar
2113 // to provide a break location. For "y=0" the "y" is at position 8 in the
2114 // barbar function therefore setting breakpoint at position 8 will break at
2115 // "y=0" and setting it higher will break after.
2116 v8::Local<v8::Function> bar = CompileFunction(&env,
2117 "y = 0;"
2118 "x = 'Goodbye, world!';"
2119 "function bar(x, b) {"
2120 " var a;"
2121 " function barbar() {"
2122 " y=0; /* To ensure break location.*/"
2123 " a=x;"
2124 " };"
2125 " debug.Debug.clearAllBreakPoints();"
2126 " barbar();"
2127 " y=0;a=x;"
2128 "}",
2129 "bar");
2130 const int barbar_break_position = 8;
2131
2132 // Call bar setting breakpoint before a=x in barbar and undefined as
2133 // parameter.
2134 checks = checks_uu;
2135 v8::Handle<v8::Value> argv_bar_1[2] = {
2136 v8::Undefined(),
2137 v8::Number::New(barbar_break_position)
2138 };
2139 bar->Call(env->Global(), 2, argv_bar_1);
2140
2141 // Call bar setting breakpoint before a=x in barbar and parameter
2142 // "Hello, world!".
2143 checks = checks_hu;
2144 v8::Handle<v8::Value> argv_bar_2[2] = {
2145 v8::String::New("Hello, world!"),
2146 v8::Number::New(barbar_break_position)
2147 };
2148 bar->Call(env->Global(), 2, argv_bar_2);
2149
2150 // Call bar setting breakpoint after a=x in barbar and parameter
2151 // "Hello, world!".
2152 checks = checks_hh;
2153 v8::Handle<v8::Value> argv_bar_3[2] = {
2154 v8::String::New("Hello, world!"),
2155 v8::Number::New(barbar_break_position + 1)
2156 };
2157 bar->Call(env->Global(), 2, argv_bar_3);
2158
2159 v8::Debug::SetDebugEventListener(NULL);
2160 CheckDebuggerUnloaded();
2161}
2162
2163
2164// Simple test of the stepping mechanism using only store ICs.
2165TEST(DebugStepLinear) {
2166 v8::HandleScope scope;
2167 DebugLocalContext env;
2168
2169 // Create a function for testing stepping.
2170 v8::Local<v8::Function> foo = CompileFunction(&env,
2171 "function foo(){a=1;b=1;c=1;}",
2172 "foo");
2173 SetBreakPoint(foo, 3);
2174
2175 // Register a debug event listener which steps and counts.
2176 v8::Debug::SetDebugEventListener(DebugEventStep);
2177
2178 step_action = StepIn;
2179 break_point_hit_count = 0;
2180 foo->Call(env->Global(), 0, NULL);
2181
2182 // With stepping all break locations are hit.
2183 CHECK_EQ(4, break_point_hit_count);
2184
2185 v8::Debug::SetDebugEventListener(NULL);
2186 CheckDebuggerUnloaded();
2187
2188 // Register a debug event listener which just counts.
2189 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2190
2191 SetBreakPoint(foo, 3);
2192 break_point_hit_count = 0;
2193 foo->Call(env->Global(), 0, NULL);
2194
2195 // Without stepping only active break points are hit.
2196 CHECK_EQ(1, break_point_hit_count);
2197
2198 v8::Debug::SetDebugEventListener(NULL);
2199 CheckDebuggerUnloaded();
2200}
2201
2202
2203// Test of the stepping mechanism for keyed load in a loop.
2204TEST(DebugStepKeyedLoadLoop) {
2205 v8::HandleScope scope;
2206 DebugLocalContext env;
2207
2208 // Create a function for testing stepping of keyed load. The statement 'y=1'
2209 // is there to have more than one breakable statement in the loop, TODO(315).
2210 v8::Local<v8::Function> foo = CompileFunction(
2211 &env,
2212 "function foo(a) {\n"
2213 " var x;\n"
2214 " var len = a.length;\n"
2215 " for (var i = 0; i < len; i++) {\n"
2216 " y = 1;\n"
2217 " x = a[i];\n"
2218 " }\n"
2219 "}\n",
2220 "foo");
2221
2222 // Create array [0,1,2,3,4,5,6,7,8,9]
2223 v8::Local<v8::Array> a = v8::Array::New(10);
2224 for (int i = 0; i < 10; i++) {
2225 a->Set(v8::Number::New(i), v8::Number::New(i));
2226 }
2227
2228 // Call function without any break points to ensure inlining is in place.
2229 const int kArgc = 1;
2230 v8::Handle<v8::Value> args[kArgc] = { a };
2231 foo->Call(env->Global(), kArgc, args);
2232
2233 // Register a debug event listener which steps and counts.
2234 v8::Debug::SetDebugEventListener(DebugEventStep);
2235
2236 // Setup break point and step through the function.
2237 SetBreakPoint(foo, 3);
2238 step_action = StepNext;
2239 break_point_hit_count = 0;
2240 foo->Call(env->Global(), kArgc, args);
2241
2242 // With stepping all break locations are hit.
2243 CHECK_EQ(22, break_point_hit_count);
2244
2245 v8::Debug::SetDebugEventListener(NULL);
2246 CheckDebuggerUnloaded();
2247}
2248
2249
2250// Test of the stepping mechanism for keyed store in a loop.
2251TEST(DebugStepKeyedStoreLoop) {
2252 v8::HandleScope scope;
2253 DebugLocalContext env;
2254
2255 // Create a function for testing stepping of keyed store. The statement 'y=1'
2256 // is there to have more than one breakable statement in the loop, TODO(315).
2257 v8::Local<v8::Function> foo = CompileFunction(
2258 &env,
2259 "function foo(a) {\n"
2260 " var len = a.length;\n"
2261 " for (var i = 0; i < len; i++) {\n"
2262 " y = 1;\n"
2263 " a[i] = 42;\n"
2264 " }\n"
2265 "}\n",
2266 "foo");
2267
2268 // Create array [0,1,2,3,4,5,6,7,8,9]
2269 v8::Local<v8::Array> a = v8::Array::New(10);
2270 for (int i = 0; i < 10; i++) {
2271 a->Set(v8::Number::New(i), v8::Number::New(i));
2272 }
2273
2274 // Call function without any break points to ensure inlining is in place.
2275 const int kArgc = 1;
2276 v8::Handle<v8::Value> args[kArgc] = { a };
2277 foo->Call(env->Global(), kArgc, args);
2278
2279 // Register a debug event listener which steps and counts.
2280 v8::Debug::SetDebugEventListener(DebugEventStep);
2281
2282 // Setup break point and step through the function.
2283 SetBreakPoint(foo, 3);
2284 step_action = StepNext;
2285 break_point_hit_count = 0;
2286 foo->Call(env->Global(), kArgc, args);
2287
2288 // With stepping all break locations are hit.
2289 CHECK_EQ(22, break_point_hit_count);
2290
2291 v8::Debug::SetDebugEventListener(NULL);
2292 CheckDebuggerUnloaded();
2293}
2294
2295
2296// Test the stepping mechanism with different ICs.
2297TEST(DebugStepLinearMixedICs) {
2298 v8::HandleScope scope;
2299 DebugLocalContext env;
2300
2301 // Create a function for testing stepping.
2302 v8::Local<v8::Function> foo = CompileFunction(&env,
2303 "function bar() {};"
2304 "function foo() {"
2305 " var x;"
2306 " var index='name';"
2307 " var y = {};"
2308 " a=1;b=2;x=a;y[index]=3;x=y[index];bar();}", "foo");
2309 SetBreakPoint(foo, 0);
2310
2311 // Register a debug event listener which steps and counts.
2312 v8::Debug::SetDebugEventListener(DebugEventStep);
2313
2314 step_action = StepIn;
2315 break_point_hit_count = 0;
2316 foo->Call(env->Global(), 0, NULL);
2317
2318 // With stepping all break locations are hit.
2319 CHECK_EQ(8, break_point_hit_count);
2320
2321 v8::Debug::SetDebugEventListener(NULL);
2322 CheckDebuggerUnloaded();
2323
2324 // Register a debug event listener which just counts.
2325 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2326
2327 SetBreakPoint(foo, 0);
2328 break_point_hit_count = 0;
2329 foo->Call(env->Global(), 0, NULL);
2330
2331 // Without stepping only active break points are hit.
2332 CHECK_EQ(1, break_point_hit_count);
2333
2334 v8::Debug::SetDebugEventListener(NULL);
2335 CheckDebuggerUnloaded();
2336}
2337
2338
2339TEST(DebugStepIf) {
2340 v8::HandleScope scope;
2341 DebugLocalContext env;
2342
2343 // Register a debug event listener which steps and counts.
2344 v8::Debug::SetDebugEventListener(DebugEventStep);
2345
2346 // Create a function for testing stepping.
2347 const int argc = 1;
2348 const char* src = "function foo(x) { "
2349 " a = 1;"
2350 " if (x) {"
2351 " b = 1;"
2352 " } else {"
2353 " c = 1;"
2354 " d = 1;"
2355 " }"
2356 "}";
2357 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2358 SetBreakPoint(foo, 0);
2359
2360 // Stepping through the true part.
2361 step_action = StepIn;
2362 break_point_hit_count = 0;
2363 v8::Handle<v8::Value> argv_true[argc] = { v8::True() };
2364 foo->Call(env->Global(), argc, argv_true);
2365 CHECK_EQ(3, break_point_hit_count);
2366
2367 // Stepping through the false part.
2368 step_action = StepIn;
2369 break_point_hit_count = 0;
2370 v8::Handle<v8::Value> argv_false[argc] = { v8::False() };
2371 foo->Call(env->Global(), argc, argv_false);
2372 CHECK_EQ(4, break_point_hit_count);
2373
2374 // Get rid of the debug event listener.
2375 v8::Debug::SetDebugEventListener(NULL);
2376 CheckDebuggerUnloaded();
2377}
2378
2379
2380TEST(DebugStepSwitch) {
2381 v8::HandleScope scope;
2382 DebugLocalContext env;
2383
2384 // Register a debug event listener which steps and counts.
2385 v8::Debug::SetDebugEventListener(DebugEventStep);
2386
2387 // Create a function for testing stepping.
2388 const int argc = 1;
2389 const char* src = "function foo(x) { "
2390 " a = 1;"
2391 " switch (x) {"
2392 " case 1:"
2393 " b = 1;"
2394 " case 2:"
2395 " c = 1;"
2396 " break;"
2397 " case 3:"
2398 " d = 1;"
2399 " e = 1;"
2400 " break;"
2401 " }"
2402 "}";
2403 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2404 SetBreakPoint(foo, 0);
2405
2406 // One case with fall-through.
2407 step_action = StepIn;
2408 break_point_hit_count = 0;
2409 v8::Handle<v8::Value> argv_1[argc] = { v8::Number::New(1) };
2410 foo->Call(env->Global(), argc, argv_1);
2411 CHECK_EQ(4, break_point_hit_count);
2412
2413 // Another case.
2414 step_action = StepIn;
2415 break_point_hit_count = 0;
2416 v8::Handle<v8::Value> argv_2[argc] = { v8::Number::New(2) };
2417 foo->Call(env->Global(), argc, argv_2);
2418 CHECK_EQ(3, break_point_hit_count);
2419
2420 // Last case.
2421 step_action = StepIn;
2422 break_point_hit_count = 0;
2423 v8::Handle<v8::Value> argv_3[argc] = { v8::Number::New(3) };
2424 foo->Call(env->Global(), argc, argv_3);
2425 CHECK_EQ(4, break_point_hit_count);
2426
2427 // Get rid of the debug event listener.
2428 v8::Debug::SetDebugEventListener(NULL);
2429 CheckDebuggerUnloaded();
2430}
2431
2432
2433TEST(DebugStepFor) {
2434 v8::HandleScope scope;
2435 DebugLocalContext env;
2436
2437 // Register a debug event listener which steps and counts.
2438 v8::Debug::SetDebugEventListener(DebugEventStep);
2439
2440 // Create a function for testing stepping.
2441 const int argc = 1;
2442 const char* src = "function foo(x) { "
2443 " a = 1;"
2444 " for (i = 0; i < x; i++) {"
2445 " b = 1;"
2446 " }"
2447 "}";
2448 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2449 SetBreakPoint(foo, 8); // "a = 1;"
2450
2451 // Looping 10 times.
2452 step_action = StepIn;
2453 break_point_hit_count = 0;
2454 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
2455 foo->Call(env->Global(), argc, argv_10);
2456 CHECK_EQ(23, break_point_hit_count);
2457
2458 // Looping 100 times.
2459 step_action = StepIn;
2460 break_point_hit_count = 0;
2461 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
2462 foo->Call(env->Global(), argc, argv_100);
2463 CHECK_EQ(203, break_point_hit_count);
2464
2465 // Get rid of the debug event listener.
2466 v8::Debug::SetDebugEventListener(NULL);
2467 CheckDebuggerUnloaded();
2468}
2469
2470
2471TEST(StepInOutSimple) {
2472 v8::HandleScope scope;
2473 DebugLocalContext env;
2474
2475 // Create a function for checking the function when hitting a break point.
2476 frame_function_name = CompileFunction(&env,
2477 frame_function_name_source,
2478 "frame_function_name");
2479
2480 // Register a debug event listener which steps and counts.
2481 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
2482
2483 // Create functions for testing stepping.
2484 const char* src = "function a() {b();c();}; "
2485 "function b() {c();}; "
2486 "function c() {}; ";
2487 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
2488 SetBreakPoint(a, 0);
2489
2490 // Step through invocation of a with step in.
2491 step_action = StepIn;
2492 break_point_hit_count = 0;
2493 expected_step_sequence = "abcbaca";
2494 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00002495 CHECK_EQ(StrLength(expected_step_sequence),
2496 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002497
2498 // Step through invocation of a with step next.
2499 step_action = StepNext;
2500 break_point_hit_count = 0;
2501 expected_step_sequence = "aaa";
2502 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00002503 CHECK_EQ(StrLength(expected_step_sequence),
2504 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002505
2506 // Step through invocation of a with step out.
2507 step_action = StepOut;
2508 break_point_hit_count = 0;
2509 expected_step_sequence = "a";
2510 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00002511 CHECK_EQ(StrLength(expected_step_sequence),
2512 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002513
2514 // Get rid of the debug event listener.
2515 v8::Debug::SetDebugEventListener(NULL);
2516 CheckDebuggerUnloaded();
2517}
2518
2519
2520TEST(StepInOutTree) {
2521 v8::HandleScope scope;
2522 DebugLocalContext env;
2523
2524 // Create a function for checking the function when hitting a break point.
2525 frame_function_name = CompileFunction(&env,
2526 frame_function_name_source,
2527 "frame_function_name");
2528
2529 // Register a debug event listener which steps and counts.
2530 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
2531
2532 // Create functions for testing stepping.
2533 const char* src = "function a() {b(c(d()),d());c(d());d()}; "
2534 "function b(x,y) {c();}; "
2535 "function c(x) {}; "
2536 "function d() {}; ";
2537 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
2538 SetBreakPoint(a, 0);
2539
2540 // Step through invocation of a with step in.
2541 step_action = StepIn;
2542 break_point_hit_count = 0;
2543 expected_step_sequence = "adacadabcbadacada";
2544 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00002545 CHECK_EQ(StrLength(expected_step_sequence),
2546 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002547
2548 // Step through invocation of a with step next.
2549 step_action = StepNext;
2550 break_point_hit_count = 0;
2551 expected_step_sequence = "aaaa";
2552 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00002553 CHECK_EQ(StrLength(expected_step_sequence),
2554 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002555
2556 // Step through invocation of a with step out.
2557 step_action = StepOut;
2558 break_point_hit_count = 0;
2559 expected_step_sequence = "a";
2560 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00002561 CHECK_EQ(StrLength(expected_step_sequence),
2562 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002563
2564 // Get rid of the debug event listener.
2565 v8::Debug::SetDebugEventListener(NULL);
2566 CheckDebuggerUnloaded(true);
2567}
2568
2569
2570TEST(StepInOutBranch) {
2571 v8::HandleScope scope;
2572 DebugLocalContext env;
2573
2574 // Create a function for checking the function when hitting a break point.
2575 frame_function_name = CompileFunction(&env,
2576 frame_function_name_source,
2577 "frame_function_name");
2578
2579 // Register a debug event listener which steps and counts.
2580 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
2581
2582 // Create functions for testing stepping.
2583 const char* src = "function a() {b(false);c();}; "
2584 "function b(x) {if(x){c();};}; "
2585 "function c() {}; ";
2586 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
2587 SetBreakPoint(a, 0);
2588
2589 // Step through invocation of a.
2590 step_action = StepIn;
2591 break_point_hit_count = 0;
2592 expected_step_sequence = "abaca";
2593 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00002594 CHECK_EQ(StrLength(expected_step_sequence),
2595 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002596
2597 // Get rid of the debug event listener.
2598 v8::Debug::SetDebugEventListener(NULL);
2599 CheckDebuggerUnloaded();
2600}
2601
2602
2603// Test that step in does not step into native functions.
2604TEST(DebugStepNatives) {
2605 v8::HandleScope scope;
2606 DebugLocalContext env;
2607
2608 // Create a function for testing stepping.
2609 v8::Local<v8::Function> foo = CompileFunction(
2610 &env,
2611 "function foo(){debugger;Math.sin(1);}",
2612 "foo");
2613
2614 // Register a debug event listener which steps and counts.
2615 v8::Debug::SetDebugEventListener(DebugEventStep);
2616
2617 step_action = StepIn;
2618 break_point_hit_count = 0;
2619 foo->Call(env->Global(), 0, NULL);
2620
2621 // With stepping all break locations are hit.
2622 CHECK_EQ(3, break_point_hit_count);
2623
2624 v8::Debug::SetDebugEventListener(NULL);
2625 CheckDebuggerUnloaded();
2626
2627 // Register a debug event listener which just counts.
2628 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2629
2630 break_point_hit_count = 0;
2631 foo->Call(env->Global(), 0, NULL);
2632
2633 // Without stepping only active break points are hit.
2634 CHECK_EQ(1, break_point_hit_count);
2635
2636 v8::Debug::SetDebugEventListener(NULL);
2637 CheckDebuggerUnloaded();
2638}
2639
2640
2641// Test that step in works with function.apply.
2642TEST(DebugStepFunctionApply) {
2643 v8::HandleScope scope;
2644 DebugLocalContext env;
2645
2646 // Create a function for testing stepping.
2647 v8::Local<v8::Function> foo = CompileFunction(
2648 &env,
2649 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
2650 "function foo(){ debugger; bar.apply(this, [1,2,3]); }",
2651 "foo");
2652
2653 // Register a debug event listener which steps and counts.
2654 v8::Debug::SetDebugEventListener(DebugEventStep);
2655
2656 step_action = StepIn;
2657 break_point_hit_count = 0;
2658 foo->Call(env->Global(), 0, NULL);
2659
2660 // With stepping all break locations are hit.
2661 CHECK_EQ(6, break_point_hit_count);
2662
2663 v8::Debug::SetDebugEventListener(NULL);
2664 CheckDebuggerUnloaded();
2665
2666 // Register a debug event listener which just counts.
2667 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2668
2669 break_point_hit_count = 0;
2670 foo->Call(env->Global(), 0, NULL);
2671
2672 // Without stepping only the debugger statement is hit.
2673 CHECK_EQ(1, break_point_hit_count);
2674
2675 v8::Debug::SetDebugEventListener(NULL);
2676 CheckDebuggerUnloaded();
2677}
2678
2679
2680// Test that step in works with function.call.
2681TEST(DebugStepFunctionCall) {
2682 v8::HandleScope scope;
2683 DebugLocalContext env;
2684
2685 // Create a function for testing stepping.
2686 v8::Local<v8::Function> foo = CompileFunction(
2687 &env,
2688 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
2689 "function foo(a){ debugger;"
2690 " if (a) {"
2691 " bar.call(this, 1, 2, 3);"
2692 " } else {"
2693 " bar.call(this, 0);"
2694 " }"
2695 "}",
2696 "foo");
2697
2698 // Register a debug event listener which steps and counts.
2699 v8::Debug::SetDebugEventListener(DebugEventStep);
2700 step_action = StepIn;
2701
2702 // Check stepping where the if condition in bar is false.
2703 break_point_hit_count = 0;
2704 foo->Call(env->Global(), 0, NULL);
2705 CHECK_EQ(4, break_point_hit_count);
2706
2707 // Check stepping where the if condition in bar is true.
2708 break_point_hit_count = 0;
2709 const int argc = 1;
2710 v8::Handle<v8::Value> argv[argc] = { v8::True() };
2711 foo->Call(env->Global(), argc, argv);
2712 CHECK_EQ(6, break_point_hit_count);
2713
2714 v8::Debug::SetDebugEventListener(NULL);
2715 CheckDebuggerUnloaded();
2716
2717 // Register a debug event listener which just counts.
2718 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2719
2720 break_point_hit_count = 0;
2721 foo->Call(env->Global(), 0, NULL);
2722
2723 // Without stepping only the debugger statement is hit.
2724 CHECK_EQ(1, break_point_hit_count);
2725
2726 v8::Debug::SetDebugEventListener(NULL);
2727 CheckDebuggerUnloaded();
2728}
2729
2730
Steve Blockd0582a62009-12-15 09:54:21 +00002731// Tests that breakpoint will be hit if it's set in script.
2732TEST(PauseInScript) {
2733 v8::HandleScope scope;
2734 DebugLocalContext env;
2735 env.ExposeDebug();
2736
2737 // Register a debug event listener which counts.
2738 v8::Debug::SetDebugEventListener(DebugEventCounter);
2739
2740 // Create a script that returns a function.
2741 const char* src = "(function (evt) {})";
2742 const char* script_name = "StepInHandlerTest";
2743
2744 // Set breakpoint in the script.
2745 SetScriptBreakPointByNameFromJS(script_name, 0, -1);
2746 break_point_hit_count = 0;
2747
2748 v8::ScriptOrigin origin(v8::String::New(script_name), v8::Integer::New(0));
2749 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(src),
2750 &origin);
2751 v8::Local<v8::Value> r = script->Run();
2752
2753 CHECK(r->IsFunction());
2754 CHECK_EQ(1, break_point_hit_count);
2755
2756 // Get rid of the debug event listener.
2757 v8::Debug::SetDebugEventListener(NULL);
2758 CheckDebuggerUnloaded();
2759}
2760
2761
Steve Blocka7e24c12009-10-30 11:49:00 +00002762// Test break on exceptions. For each exception break combination the number
2763// of debug event exception callbacks and message callbacks are collected. The
2764// number of debug event exception callbacks are used to check that the
2765// debugger is called correctly and the number of message callbacks is used to
2766// check that uncaught exceptions are still returned even if there is a break
2767// for them.
2768TEST(BreakOnException) {
2769 v8::HandleScope scope;
2770 DebugLocalContext env;
2771 env.ExposeDebug();
2772
2773 v8::internal::Top::TraceException(false);
2774
2775 // Create functions for testing break on exception.
2776 v8::Local<v8::Function> throws =
2777 CompileFunction(&env, "function throws(){throw 1;}", "throws");
2778 v8::Local<v8::Function> caught =
2779 CompileFunction(&env,
2780 "function caught(){try {throws();} catch(e) {};}",
2781 "caught");
2782 v8::Local<v8::Function> notCaught =
2783 CompileFunction(&env, "function notCaught(){throws();}", "notCaught");
2784
2785 v8::V8::AddMessageListener(MessageCallbackCount);
2786 v8::Debug::SetDebugEventListener(DebugEventCounter);
2787
2788 // Initial state should be break on uncaught exception.
2789 DebugEventCounterClear();
2790 MessageCallbackCountClear();
2791 caught->Call(env->Global(), 0, NULL);
2792 CHECK_EQ(0, exception_hit_count);
2793 CHECK_EQ(0, uncaught_exception_hit_count);
2794 CHECK_EQ(0, message_callback_count);
2795 notCaught->Call(env->Global(), 0, NULL);
2796 CHECK_EQ(1, exception_hit_count);
2797 CHECK_EQ(1, uncaught_exception_hit_count);
2798 CHECK_EQ(1, message_callback_count);
2799
2800 // No break on exception
2801 DebugEventCounterClear();
2802 MessageCallbackCountClear();
2803 ChangeBreakOnException(false, false);
2804 caught->Call(env->Global(), 0, NULL);
2805 CHECK_EQ(0, exception_hit_count);
2806 CHECK_EQ(0, uncaught_exception_hit_count);
2807 CHECK_EQ(0, message_callback_count);
2808 notCaught->Call(env->Global(), 0, NULL);
2809 CHECK_EQ(0, exception_hit_count);
2810 CHECK_EQ(0, uncaught_exception_hit_count);
2811 CHECK_EQ(1, message_callback_count);
2812
2813 // Break on uncaught exception
2814 DebugEventCounterClear();
2815 MessageCallbackCountClear();
2816 ChangeBreakOnException(false, true);
2817 caught->Call(env->Global(), 0, NULL);
2818 CHECK_EQ(0, exception_hit_count);
2819 CHECK_EQ(0, uncaught_exception_hit_count);
2820 CHECK_EQ(0, message_callback_count);
2821 notCaught->Call(env->Global(), 0, NULL);
2822 CHECK_EQ(1, exception_hit_count);
2823 CHECK_EQ(1, uncaught_exception_hit_count);
2824 CHECK_EQ(1, message_callback_count);
2825
2826 // Break on exception and uncaught exception
2827 DebugEventCounterClear();
2828 MessageCallbackCountClear();
2829 ChangeBreakOnException(true, true);
2830 caught->Call(env->Global(), 0, NULL);
2831 CHECK_EQ(1, exception_hit_count);
2832 CHECK_EQ(0, uncaught_exception_hit_count);
2833 CHECK_EQ(0, message_callback_count);
2834 notCaught->Call(env->Global(), 0, NULL);
2835 CHECK_EQ(2, exception_hit_count);
2836 CHECK_EQ(1, uncaught_exception_hit_count);
2837 CHECK_EQ(1, message_callback_count);
2838
2839 // Break on exception
2840 DebugEventCounterClear();
2841 MessageCallbackCountClear();
2842 ChangeBreakOnException(true, false);
2843 caught->Call(env->Global(), 0, NULL);
2844 CHECK_EQ(1, exception_hit_count);
2845 CHECK_EQ(0, uncaught_exception_hit_count);
2846 CHECK_EQ(0, message_callback_count);
2847 notCaught->Call(env->Global(), 0, NULL);
2848 CHECK_EQ(2, exception_hit_count);
2849 CHECK_EQ(1, uncaught_exception_hit_count);
2850 CHECK_EQ(1, message_callback_count);
2851
2852 // No break on exception using JavaScript
2853 DebugEventCounterClear();
2854 MessageCallbackCountClear();
2855 ChangeBreakOnExceptionFromJS(false, false);
2856 caught->Call(env->Global(), 0, NULL);
2857 CHECK_EQ(0, exception_hit_count);
2858 CHECK_EQ(0, uncaught_exception_hit_count);
2859 CHECK_EQ(0, message_callback_count);
2860 notCaught->Call(env->Global(), 0, NULL);
2861 CHECK_EQ(0, exception_hit_count);
2862 CHECK_EQ(0, uncaught_exception_hit_count);
2863 CHECK_EQ(1, message_callback_count);
2864
2865 // Break on uncaught exception using JavaScript
2866 DebugEventCounterClear();
2867 MessageCallbackCountClear();
2868 ChangeBreakOnExceptionFromJS(false, true);
2869 caught->Call(env->Global(), 0, NULL);
2870 CHECK_EQ(0, exception_hit_count);
2871 CHECK_EQ(0, uncaught_exception_hit_count);
2872 CHECK_EQ(0, message_callback_count);
2873 notCaught->Call(env->Global(), 0, NULL);
2874 CHECK_EQ(1, exception_hit_count);
2875 CHECK_EQ(1, uncaught_exception_hit_count);
2876 CHECK_EQ(1, message_callback_count);
2877
2878 // Break on exception and uncaught exception using JavaScript
2879 DebugEventCounterClear();
2880 MessageCallbackCountClear();
2881 ChangeBreakOnExceptionFromJS(true, true);
2882 caught->Call(env->Global(), 0, NULL);
2883 CHECK_EQ(1, exception_hit_count);
2884 CHECK_EQ(0, message_callback_count);
2885 CHECK_EQ(0, uncaught_exception_hit_count);
2886 notCaught->Call(env->Global(), 0, NULL);
2887 CHECK_EQ(2, exception_hit_count);
2888 CHECK_EQ(1, uncaught_exception_hit_count);
2889 CHECK_EQ(1, message_callback_count);
2890
2891 // Break on exception using JavaScript
2892 DebugEventCounterClear();
2893 MessageCallbackCountClear();
2894 ChangeBreakOnExceptionFromJS(true, false);
2895 caught->Call(env->Global(), 0, NULL);
2896 CHECK_EQ(1, exception_hit_count);
2897 CHECK_EQ(0, uncaught_exception_hit_count);
2898 CHECK_EQ(0, message_callback_count);
2899 notCaught->Call(env->Global(), 0, NULL);
2900 CHECK_EQ(2, exception_hit_count);
2901 CHECK_EQ(1, uncaught_exception_hit_count);
2902 CHECK_EQ(1, message_callback_count);
2903
2904 v8::Debug::SetDebugEventListener(NULL);
2905 CheckDebuggerUnloaded();
2906 v8::V8::RemoveMessageListeners(MessageCallbackCount);
2907}
2908
2909
2910// Test break on exception from compiler errors. When compiling using
2911// v8::Script::Compile there is no JavaScript stack whereas when compiling using
2912// eval there are JavaScript frames.
2913TEST(BreakOnCompileException) {
2914 v8::HandleScope scope;
2915 DebugLocalContext env;
2916
2917 v8::internal::Top::TraceException(false);
2918
2919 // Create a function for checking the function when hitting a break point.
2920 frame_count = CompileFunction(&env, frame_count_source, "frame_count");
2921
2922 v8::V8::AddMessageListener(MessageCallbackCount);
2923 v8::Debug::SetDebugEventListener(DebugEventCounter);
2924
2925 DebugEventCounterClear();
2926 MessageCallbackCountClear();
2927
2928 // Check initial state.
2929 CHECK_EQ(0, exception_hit_count);
2930 CHECK_EQ(0, uncaught_exception_hit_count);
2931 CHECK_EQ(0, message_callback_count);
2932 CHECK_EQ(-1, last_js_stack_height);
2933
2934 // Throws SyntaxError: Unexpected end of input
2935 v8::Script::Compile(v8::String::New("+++"));
2936 CHECK_EQ(1, exception_hit_count);
2937 CHECK_EQ(1, uncaught_exception_hit_count);
2938 CHECK_EQ(1, message_callback_count);
2939 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
2940
2941 // Throws SyntaxError: Unexpected identifier
2942 v8::Script::Compile(v8::String::New("x x"));
2943 CHECK_EQ(2, exception_hit_count);
2944 CHECK_EQ(2, uncaught_exception_hit_count);
2945 CHECK_EQ(2, message_callback_count);
2946 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
2947
2948 // Throws SyntaxError: Unexpected end of input
2949 v8::Script::Compile(v8::String::New("eval('+++')"))->Run();
2950 CHECK_EQ(3, exception_hit_count);
2951 CHECK_EQ(3, uncaught_exception_hit_count);
2952 CHECK_EQ(3, message_callback_count);
2953 CHECK_EQ(1, last_js_stack_height);
2954
2955 // Throws SyntaxError: Unexpected identifier
2956 v8::Script::Compile(v8::String::New("eval('x x')"))->Run();
2957 CHECK_EQ(4, exception_hit_count);
2958 CHECK_EQ(4, uncaught_exception_hit_count);
2959 CHECK_EQ(4, message_callback_count);
2960 CHECK_EQ(1, last_js_stack_height);
2961}
2962
2963
2964TEST(StepWithException) {
2965 v8::HandleScope scope;
2966 DebugLocalContext env;
2967
2968 // Create a function for checking the function when hitting a break point.
2969 frame_function_name = CompileFunction(&env,
2970 frame_function_name_source,
2971 "frame_function_name");
2972
2973 // Register a debug event listener which steps and counts.
2974 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
2975
2976 // Create functions for testing stepping.
2977 const char* src = "function a() { n(); }; "
2978 "function b() { c(); }; "
2979 "function c() { n(); }; "
2980 "function d() { x = 1; try { e(); } catch(x) { x = 2; } }; "
2981 "function e() { n(); }; "
2982 "function f() { x = 1; try { g(); } catch(x) { x = 2; } }; "
2983 "function g() { h(); }; "
2984 "function h() { x = 1; throw 1; }; ";
2985
2986 // Step through invocation of a.
2987 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
2988 SetBreakPoint(a, 0);
2989 step_action = StepIn;
2990 break_point_hit_count = 0;
2991 expected_step_sequence = "aa";
2992 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00002993 CHECK_EQ(StrLength(expected_step_sequence),
2994 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002995
2996 // Step through invocation of b + c.
2997 v8::Local<v8::Function> b = CompileFunction(&env, src, "b");
2998 SetBreakPoint(b, 0);
2999 step_action = StepIn;
3000 break_point_hit_count = 0;
3001 expected_step_sequence = "bcc";
3002 b->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003003 CHECK_EQ(StrLength(expected_step_sequence),
3004 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003005
3006 // Step through invocation of d + e.
3007 v8::Local<v8::Function> d = CompileFunction(&env, src, "d");
3008 SetBreakPoint(d, 0);
3009 ChangeBreakOnException(false, true);
3010 step_action = StepIn;
3011 break_point_hit_count = 0;
3012 expected_step_sequence = "dded";
3013 d->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003014 CHECK_EQ(StrLength(expected_step_sequence),
3015 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003016
3017 // Step through invocation of d + e now with break on caught exceptions.
3018 ChangeBreakOnException(true, true);
3019 step_action = StepIn;
3020 break_point_hit_count = 0;
3021 expected_step_sequence = "ddeed";
3022 d->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003023 CHECK_EQ(StrLength(expected_step_sequence),
3024 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003025
3026 // Step through invocation of f + g + h.
3027 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
3028 SetBreakPoint(f, 0);
3029 ChangeBreakOnException(false, true);
3030 step_action = StepIn;
3031 break_point_hit_count = 0;
3032 expected_step_sequence = "ffghf";
3033 f->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003034 CHECK_EQ(StrLength(expected_step_sequence),
3035 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003036
3037 // Step through invocation of f + g + h now with break on caught exceptions.
3038 ChangeBreakOnException(true, true);
3039 step_action = StepIn;
3040 break_point_hit_count = 0;
3041 expected_step_sequence = "ffghhf";
3042 f->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003043 CHECK_EQ(StrLength(expected_step_sequence),
3044 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003045
3046 // Get rid of the debug event listener.
3047 v8::Debug::SetDebugEventListener(NULL);
3048 CheckDebuggerUnloaded();
3049}
3050
3051
3052TEST(DebugBreak) {
3053 v8::HandleScope scope;
3054 DebugLocalContext env;
3055
3056 // This test should be run with option --verify-heap. As --verify-heap is
3057 // only available in debug mode only check for it in that case.
3058#ifdef DEBUG
3059 CHECK(v8::internal::FLAG_verify_heap);
3060#endif
3061
3062 // Register a debug event listener which sets the break flag and counts.
3063 v8::Debug::SetDebugEventListener(DebugEventBreak);
3064
3065 // Create a function for testing stepping.
3066 const char* src = "function f0() {}"
3067 "function f1(x1) {}"
3068 "function f2(x1,x2) {}"
3069 "function f3(x1,x2,x3) {}";
3070 v8::Local<v8::Function> f0 = CompileFunction(&env, src, "f0");
3071 v8::Local<v8::Function> f1 = CompileFunction(&env, src, "f1");
3072 v8::Local<v8::Function> f2 = CompileFunction(&env, src, "f2");
3073 v8::Local<v8::Function> f3 = CompileFunction(&env, src, "f3");
3074
3075 // Call the function to make sure it is compiled.
3076 v8::Handle<v8::Value> argv[] = { v8::Number::New(1),
3077 v8::Number::New(1),
3078 v8::Number::New(1),
3079 v8::Number::New(1) };
3080
3081 // Call all functions to make sure that they are compiled.
3082 f0->Call(env->Global(), 0, NULL);
3083 f1->Call(env->Global(), 0, NULL);
3084 f2->Call(env->Global(), 0, NULL);
3085 f3->Call(env->Global(), 0, NULL);
3086
3087 // Set the debug break flag.
3088 v8::Debug::DebugBreak();
3089
3090 // Call all functions with different argument count.
3091 break_point_hit_count = 0;
3092 for (unsigned int i = 0; i < ARRAY_SIZE(argv); i++) {
3093 f0->Call(env->Global(), i, argv);
3094 f1->Call(env->Global(), i, argv);
3095 f2->Call(env->Global(), i, argv);
3096 f3->Call(env->Global(), i, argv);
3097 }
3098
3099 // One break for each function called.
3100 CHECK_EQ(4 * ARRAY_SIZE(argv), break_point_hit_count);
3101
3102 // Get rid of the debug event listener.
3103 v8::Debug::SetDebugEventListener(NULL);
3104 CheckDebuggerUnloaded();
3105}
3106
3107
3108// Test to ensure that JavaScript code keeps running while the debug break
3109// through the stack limit flag is set but breaks are disabled.
3110TEST(DisableBreak) {
3111 v8::HandleScope scope;
3112 DebugLocalContext env;
3113
3114 // Register a debug event listener which sets the break flag and counts.
3115 v8::Debug::SetDebugEventListener(DebugEventCounter);
3116
3117 // Create a function for testing stepping.
3118 const char* src = "function f() {g()};function g(){i=0; while(i<10){i++}}";
3119 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
3120
3121 // Set the debug break flag.
3122 v8::Debug::DebugBreak();
3123
3124 // Call all functions with different argument count.
3125 break_point_hit_count = 0;
3126 f->Call(env->Global(), 0, NULL);
3127 CHECK_EQ(1, break_point_hit_count);
3128
3129 {
3130 v8::Debug::DebugBreak();
3131 v8::internal::DisableBreak disable_break(true);
3132 f->Call(env->Global(), 0, NULL);
3133 CHECK_EQ(1, break_point_hit_count);
3134 }
3135
3136 f->Call(env->Global(), 0, NULL);
3137 CHECK_EQ(2, break_point_hit_count);
3138
3139 // Get rid of the debug event listener.
3140 v8::Debug::SetDebugEventListener(NULL);
3141 CheckDebuggerUnloaded();
3142}
3143
3144
3145static v8::Handle<v8::Array> NamedEnum(const v8::AccessorInfo&) {
3146 v8::Handle<v8::Array> result = v8::Array::New(3);
3147 result->Set(v8::Integer::New(0), v8::String::New("a"));
3148 result->Set(v8::Integer::New(1), v8::String::New("b"));
3149 result->Set(v8::Integer::New(2), v8::String::New("c"));
3150 return result;
3151}
3152
3153
3154static v8::Handle<v8::Array> IndexedEnum(const v8::AccessorInfo&) {
3155 v8::Handle<v8::Array> result = v8::Array::New(2);
3156 result->Set(v8::Integer::New(0), v8::Number::New(1));
3157 result->Set(v8::Integer::New(1), v8::Number::New(10));
3158 return result;
3159}
3160
3161
3162static v8::Handle<v8::Value> NamedGetter(v8::Local<v8::String> name,
3163 const v8::AccessorInfo& info) {
3164 v8::String::AsciiValue n(name);
3165 if (strcmp(*n, "a") == 0) {
3166 return v8::String::New("AA");
3167 } else if (strcmp(*n, "b") == 0) {
3168 return v8::String::New("BB");
3169 } else if (strcmp(*n, "c") == 0) {
3170 return v8::String::New("CC");
3171 } else {
3172 return v8::Undefined();
3173 }
3174
3175 return name;
3176}
3177
3178
3179static v8::Handle<v8::Value> IndexedGetter(uint32_t index,
3180 const v8::AccessorInfo& info) {
3181 return v8::Number::New(index + 1);
3182}
3183
3184
3185TEST(InterceptorPropertyMirror) {
3186 // Create a V8 environment with debug access.
3187 v8::HandleScope scope;
3188 DebugLocalContext env;
3189 env.ExposeDebug();
3190
3191 // Create object with named interceptor.
3192 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
3193 named->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
3194 env->Global()->Set(v8::String::New("intercepted_named"),
3195 named->NewInstance());
3196
3197 // Create object with indexed interceptor.
3198 v8::Handle<v8::ObjectTemplate> indexed = v8::ObjectTemplate::New();
3199 indexed->SetIndexedPropertyHandler(IndexedGetter,
3200 NULL,
3201 NULL,
3202 NULL,
3203 IndexedEnum);
3204 env->Global()->Set(v8::String::New("intercepted_indexed"),
3205 indexed->NewInstance());
3206
3207 // Create object with both named and indexed interceptor.
3208 v8::Handle<v8::ObjectTemplate> both = v8::ObjectTemplate::New();
3209 both->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
3210 both->SetIndexedPropertyHandler(IndexedGetter, NULL, NULL, NULL, IndexedEnum);
3211 env->Global()->Set(v8::String::New("intercepted_both"), both->NewInstance());
3212
3213 // Get mirrors for the three objects with interceptor.
3214 CompileRun(
3215 "named_mirror = debug.MakeMirror(intercepted_named);"
3216 "indexed_mirror = debug.MakeMirror(intercepted_indexed);"
3217 "both_mirror = debug.MakeMirror(intercepted_both)");
3218 CHECK(CompileRun(
3219 "named_mirror instanceof debug.ObjectMirror")->BooleanValue());
3220 CHECK(CompileRun(
3221 "indexed_mirror instanceof debug.ObjectMirror")->BooleanValue());
3222 CHECK(CompileRun(
3223 "both_mirror instanceof debug.ObjectMirror")->BooleanValue());
3224
3225 // Get the property names from the interceptors
3226 CompileRun(
3227 "named_names = named_mirror.propertyNames();"
3228 "indexed_names = indexed_mirror.propertyNames();"
3229 "both_names = both_mirror.propertyNames()");
3230 CHECK_EQ(3, CompileRun("named_names.length")->Int32Value());
3231 CHECK_EQ(2, CompileRun("indexed_names.length")->Int32Value());
3232 CHECK_EQ(5, CompileRun("both_names.length")->Int32Value());
3233
3234 // Check the expected number of properties.
3235 const char* source;
3236 source = "named_mirror.properties().length";
3237 CHECK_EQ(3, CompileRun(source)->Int32Value());
3238
3239 source = "indexed_mirror.properties().length";
3240 CHECK_EQ(2, CompileRun(source)->Int32Value());
3241
3242 source = "both_mirror.properties().length";
3243 CHECK_EQ(5, CompileRun(source)->Int32Value());
3244
3245 // 1 is PropertyKind.Named;
3246 source = "both_mirror.properties(1).length";
3247 CHECK_EQ(3, CompileRun(source)->Int32Value());
3248
3249 // 2 is PropertyKind.Indexed;
3250 source = "both_mirror.properties(2).length";
3251 CHECK_EQ(2, CompileRun(source)->Int32Value());
3252
3253 // 3 is PropertyKind.Named | PropertyKind.Indexed;
3254 source = "both_mirror.properties(3).length";
3255 CHECK_EQ(5, CompileRun(source)->Int32Value());
3256
3257 // Get the interceptor properties for the object with only named interceptor.
3258 CompileRun("named_values = named_mirror.properties()");
3259
3260 // Check that the properties are interceptor properties.
3261 for (int i = 0; i < 3; i++) {
3262 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
3263 OS::SNPrintF(buffer,
3264 "named_values[%d] instanceof debug.PropertyMirror", i);
3265 CHECK(CompileRun(buffer.start())->BooleanValue());
3266
3267 // 4 is PropertyType.Interceptor
3268 OS::SNPrintF(buffer, "named_values[%d].propertyType()", i);
3269 CHECK_EQ(4, CompileRun(buffer.start())->Int32Value());
3270
3271 OS::SNPrintF(buffer, "named_values[%d].isNative()", i);
3272 CHECK(CompileRun(buffer.start())->BooleanValue());
3273 }
3274
3275 // Get the interceptor properties for the object with only indexed
3276 // interceptor.
3277 CompileRun("indexed_values = indexed_mirror.properties()");
3278
3279 // Check that the properties are interceptor properties.
3280 for (int i = 0; i < 2; i++) {
3281 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
3282 OS::SNPrintF(buffer,
3283 "indexed_values[%d] instanceof debug.PropertyMirror", i);
3284 CHECK(CompileRun(buffer.start())->BooleanValue());
3285 }
3286
3287 // Get the interceptor properties for the object with both types of
3288 // interceptors.
3289 CompileRun("both_values = both_mirror.properties()");
3290
3291 // Check that the properties are interceptor properties.
3292 for (int i = 0; i < 5; i++) {
3293 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
3294 OS::SNPrintF(buffer, "both_values[%d] instanceof debug.PropertyMirror", i);
3295 CHECK(CompileRun(buffer.start())->BooleanValue());
3296 }
3297
3298 // Check the property names.
3299 source = "both_values[0].name() == 'a'";
3300 CHECK(CompileRun(source)->BooleanValue());
3301
3302 source = "both_values[1].name() == 'b'";
3303 CHECK(CompileRun(source)->BooleanValue());
3304
3305 source = "both_values[2].name() == 'c'";
3306 CHECK(CompileRun(source)->BooleanValue());
3307
3308 source = "both_values[3].name() == 1";
3309 CHECK(CompileRun(source)->BooleanValue());
3310
3311 source = "both_values[4].name() == 10";
3312 CHECK(CompileRun(source)->BooleanValue());
3313}
3314
3315
3316TEST(HiddenPrototypePropertyMirror) {
3317 // Create a V8 environment with debug access.
3318 v8::HandleScope scope;
3319 DebugLocalContext env;
3320 env.ExposeDebug();
3321
3322 v8::Handle<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
3323 t0->InstanceTemplate()->Set(v8::String::New("x"), v8::Number::New(0));
3324 v8::Handle<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
3325 t1->SetHiddenPrototype(true);
3326 t1->InstanceTemplate()->Set(v8::String::New("y"), v8::Number::New(1));
3327 v8::Handle<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
3328 t2->SetHiddenPrototype(true);
3329 t2->InstanceTemplate()->Set(v8::String::New("z"), v8::Number::New(2));
3330 v8::Handle<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
3331 t3->InstanceTemplate()->Set(v8::String::New("u"), v8::Number::New(3));
3332
3333 // Create object and set them on the global object.
3334 v8::Handle<v8::Object> o0 = t0->GetFunction()->NewInstance();
3335 env->Global()->Set(v8::String::New("o0"), o0);
3336 v8::Handle<v8::Object> o1 = t1->GetFunction()->NewInstance();
3337 env->Global()->Set(v8::String::New("o1"), o1);
3338 v8::Handle<v8::Object> o2 = t2->GetFunction()->NewInstance();
3339 env->Global()->Set(v8::String::New("o2"), o2);
3340 v8::Handle<v8::Object> o3 = t3->GetFunction()->NewInstance();
3341 env->Global()->Set(v8::String::New("o3"), o3);
3342
3343 // Get mirrors for the four objects.
3344 CompileRun(
3345 "o0_mirror = debug.MakeMirror(o0);"
3346 "o1_mirror = debug.MakeMirror(o1);"
3347 "o2_mirror = debug.MakeMirror(o2);"
3348 "o3_mirror = debug.MakeMirror(o3)");
3349 CHECK(CompileRun("o0_mirror instanceof debug.ObjectMirror")->BooleanValue());
3350 CHECK(CompileRun("o1_mirror instanceof debug.ObjectMirror")->BooleanValue());
3351 CHECK(CompileRun("o2_mirror instanceof debug.ObjectMirror")->BooleanValue());
3352 CHECK(CompileRun("o3_mirror instanceof debug.ObjectMirror")->BooleanValue());
3353
3354 // Check that each object has one property.
3355 CHECK_EQ(1, CompileRun(
3356 "o0_mirror.propertyNames().length")->Int32Value());
3357 CHECK_EQ(1, CompileRun(
3358 "o1_mirror.propertyNames().length")->Int32Value());
3359 CHECK_EQ(1, CompileRun(
3360 "o2_mirror.propertyNames().length")->Int32Value());
3361 CHECK_EQ(1, CompileRun(
3362 "o3_mirror.propertyNames().length")->Int32Value());
3363
3364 // Set o1 as prototype for o0. o1 has the hidden prototype flag so all
3365 // properties on o1 should be seen on o0.
3366 o0->Set(v8::String::New("__proto__"), o1);
3367 CHECK_EQ(2, CompileRun(
3368 "o0_mirror.propertyNames().length")->Int32Value());
3369 CHECK_EQ(0, CompileRun(
3370 "o0_mirror.property('x').value().value()")->Int32Value());
3371 CHECK_EQ(1, CompileRun(
3372 "o0_mirror.property('y').value().value()")->Int32Value());
3373
3374 // Set o2 as prototype for o0 (it will end up after o1 as o1 has the hidden
3375 // prototype flag. o2 also has the hidden prototype flag so all properties
3376 // on o2 should be seen on o0 as well as properties on o1.
3377 o0->Set(v8::String::New("__proto__"), o2);
3378 CHECK_EQ(3, CompileRun(
3379 "o0_mirror.propertyNames().length")->Int32Value());
3380 CHECK_EQ(0, CompileRun(
3381 "o0_mirror.property('x').value().value()")->Int32Value());
3382 CHECK_EQ(1, CompileRun(
3383 "o0_mirror.property('y').value().value()")->Int32Value());
3384 CHECK_EQ(2, CompileRun(
3385 "o0_mirror.property('z').value().value()")->Int32Value());
3386
3387 // Set o3 as prototype for o0 (it will end up after o1 and o2 as both o1 and
3388 // o2 has the hidden prototype flag. o3 does not have the hidden prototype
3389 // flag so properties on o3 should not be seen on o0 whereas the properties
3390 // from o1 and o2 should still be seen on o0.
3391 // Final prototype chain: o0 -> o1 -> o2 -> o3
3392 // Hidden prototypes: ^^ ^^
3393 o0->Set(v8::String::New("__proto__"), o3);
3394 CHECK_EQ(3, CompileRun(
3395 "o0_mirror.propertyNames().length")->Int32Value());
3396 CHECK_EQ(1, CompileRun(
3397 "o3_mirror.propertyNames().length")->Int32Value());
3398 CHECK_EQ(0, CompileRun(
3399 "o0_mirror.property('x').value().value()")->Int32Value());
3400 CHECK_EQ(1, CompileRun(
3401 "o0_mirror.property('y').value().value()")->Int32Value());
3402 CHECK_EQ(2, CompileRun(
3403 "o0_mirror.property('z').value().value()")->Int32Value());
3404 CHECK(CompileRun("o0_mirror.property('u').isUndefined()")->BooleanValue());
3405
3406 // The prototype (__proto__) for o0 should be o3 as o1 and o2 are hidden.
3407 CHECK(CompileRun("o0_mirror.protoObject() == o3_mirror")->BooleanValue());
3408}
3409
3410
3411static v8::Handle<v8::Value> ProtperyXNativeGetter(
3412 v8::Local<v8::String> property, const v8::AccessorInfo& info) {
3413 return v8::Integer::New(10);
3414}
3415
3416
3417TEST(NativeGetterPropertyMirror) {
3418 // Create a V8 environment with debug access.
3419 v8::HandleScope scope;
3420 DebugLocalContext env;
3421 env.ExposeDebug();
3422
3423 v8::Handle<v8::String> name = v8::String::New("x");
3424 // Create object with named accessor.
3425 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
3426 named->SetAccessor(name, &ProtperyXNativeGetter, NULL,
3427 v8::Handle<v8::Value>(), v8::DEFAULT, v8::None);
3428
3429 // Create object with named property getter.
3430 env->Global()->Set(v8::String::New("instance"), named->NewInstance());
3431 CHECK_EQ(10, CompileRun("instance.x")->Int32Value());
3432
3433 // Get mirror for the object with property getter.
3434 CompileRun("instance_mirror = debug.MakeMirror(instance);");
3435 CHECK(CompileRun(
3436 "instance_mirror instanceof debug.ObjectMirror")->BooleanValue());
3437
3438 CompileRun("named_names = instance_mirror.propertyNames();");
3439 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
3440 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue());
3441 CHECK(CompileRun(
3442 "instance_mirror.property('x').value().isNumber()")->BooleanValue());
3443 CHECK(CompileRun(
3444 "instance_mirror.property('x').value().value() == 10")->BooleanValue());
3445}
3446
3447
3448static v8::Handle<v8::Value> ProtperyXNativeGetterThrowingError(
3449 v8::Local<v8::String> property, const v8::AccessorInfo& info) {
3450 return CompileRun("throw new Error('Error message');");
3451}
3452
3453
3454TEST(NativeGetterThrowingErrorPropertyMirror) {
3455 // Create a V8 environment with debug access.
3456 v8::HandleScope scope;
3457 DebugLocalContext env;
3458 env.ExposeDebug();
3459
3460 v8::Handle<v8::String> name = v8::String::New("x");
3461 // Create object with named accessor.
3462 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
3463 named->SetAccessor(name, &ProtperyXNativeGetterThrowingError, NULL,
3464 v8::Handle<v8::Value>(), v8::DEFAULT, v8::None);
3465
3466 // Create object with named property getter.
3467 env->Global()->Set(v8::String::New("instance"), named->NewInstance());
3468
3469 // Get mirror for the object with property getter.
3470 CompileRun("instance_mirror = debug.MakeMirror(instance);");
3471 CHECK(CompileRun(
3472 "instance_mirror instanceof debug.ObjectMirror")->BooleanValue());
3473 CompileRun("named_names = instance_mirror.propertyNames();");
3474 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
3475 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue());
3476 CHECK(CompileRun(
3477 "instance_mirror.property('x').value().isError()")->BooleanValue());
3478
3479 // Check that the message is that passed to the Error constructor.
3480 CHECK(CompileRun(
3481 "instance_mirror.property('x').value().message() == 'Error message'")->
3482 BooleanValue());
3483}
3484
3485
Steve Blockd0582a62009-12-15 09:54:21 +00003486// Test that hidden properties object is not returned as an unnamed property
3487// among regular properties.
3488// See http://crbug.com/26491
3489TEST(NoHiddenProperties) {
3490 // Create a V8 environment with debug access.
3491 v8::HandleScope scope;
3492 DebugLocalContext env;
3493 env.ExposeDebug();
3494
3495 // Create an object in the global scope.
3496 const char* source = "var obj = {a: 1};";
3497 v8::Script::Compile(v8::String::New(source))->Run();
3498 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
3499 env->Global()->Get(v8::String::New("obj")));
3500 // Set a hidden property on the object.
3501 obj->SetHiddenValue(v8::String::New("v8::test-debug::a"),
3502 v8::Int32::New(11));
3503
3504 // Get mirror for the object with property getter.
3505 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
3506 CHECK(CompileRun(
3507 "obj_mirror instanceof debug.ObjectMirror")->BooleanValue());
3508 CompileRun("var named_names = obj_mirror.propertyNames();");
3509 // There should be exactly one property. But there is also an unnamed
3510 // property whose value is hidden properties dictionary. The latter
3511 // property should not be in the list of reguar properties.
3512 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
3513 CHECK(CompileRun("named_names[0] == 'a'")->BooleanValue());
3514 CHECK(CompileRun(
3515 "obj_mirror.property('a').value().value() == 1")->BooleanValue());
3516
3517 // Object created by t0 will become hidden prototype of object 'obj'.
3518 v8::Handle<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
3519 t0->InstanceTemplate()->Set(v8::String::New("b"), v8::Number::New(2));
3520 t0->SetHiddenPrototype(true);
3521 v8::Handle<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
3522 t1->InstanceTemplate()->Set(v8::String::New("c"), v8::Number::New(3));
3523
3524 // Create proto objects, add hidden properties to them and set them on
3525 // the global object.
3526 v8::Handle<v8::Object> protoObj = t0->GetFunction()->NewInstance();
3527 protoObj->SetHiddenValue(v8::String::New("v8::test-debug::b"),
3528 v8::Int32::New(12));
3529 env->Global()->Set(v8::String::New("protoObj"), protoObj);
3530 v8::Handle<v8::Object> grandProtoObj = t1->GetFunction()->NewInstance();
3531 grandProtoObj->SetHiddenValue(v8::String::New("v8::test-debug::c"),
3532 v8::Int32::New(13));
3533 env->Global()->Set(v8::String::New("grandProtoObj"), grandProtoObj);
3534
3535 // Setting prototypes: obj->protoObj->grandProtoObj
3536 protoObj->Set(v8::String::New("__proto__"), grandProtoObj);
3537 obj->Set(v8::String::New("__proto__"), protoObj);
3538
3539 // Get mirror for the object with property getter.
3540 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
3541 CHECK(CompileRun(
3542 "obj_mirror instanceof debug.ObjectMirror")->BooleanValue());
3543 CompileRun("var named_names = obj_mirror.propertyNames();");
3544 // There should be exactly two properties - one from the object itself and
3545 // another from its hidden prototype.
3546 CHECK_EQ(2, CompileRun("named_names.length")->Int32Value());
3547 CHECK(CompileRun("named_names.sort(); named_names[0] == 'a' &&"
3548 "named_names[1] == 'b'")->BooleanValue());
3549 CHECK(CompileRun(
3550 "obj_mirror.property('a').value().value() == 1")->BooleanValue());
3551 CHECK(CompileRun(
3552 "obj_mirror.property('b').value().value() == 2")->BooleanValue());
3553}
3554
Steve Blocka7e24c12009-10-30 11:49:00 +00003555
3556// Multithreaded tests of JSON debugger protocol
3557
3558// Support classes
3559
3560// Copies a C string to a 16-bit string. Does not check for buffer overflow.
3561// Does not use the V8 engine to convert strings, so it can be used
3562// in any thread. Returns the length of the string.
3563int AsciiToUtf16(const char* input_buffer, uint16_t* output_buffer) {
3564 int i;
3565 for (i = 0; input_buffer[i] != '\0'; ++i) {
3566 // ASCII does not use chars > 127, but be careful anyway.
3567 output_buffer[i] = static_cast<unsigned char>(input_buffer[i]);
3568 }
3569 output_buffer[i] = 0;
3570 return i;
3571}
3572
3573// Copies a 16-bit string to a C string by dropping the high byte of
3574// each character. Does not check for buffer overflow.
3575// Can be used in any thread. Requires string length as an input.
3576int Utf16ToAscii(const uint16_t* input_buffer, int length,
3577 char* output_buffer) {
3578 for (int i = 0; i < length; ++i) {
3579 output_buffer[i] = static_cast<char>(input_buffer[i]);
3580 }
3581 output_buffer[length] = '\0';
3582 return length;
3583}
3584
3585// Provides synchronization between k threads, where k is an input to the
3586// constructor. The Wait() call blocks a thread until it is called for the
3587// k'th time, then all calls return. Each ThreadBarrier object can only
3588// be used once.
3589class ThreadBarrier {
3590 public:
3591 explicit ThreadBarrier(int num_threads);
3592 ~ThreadBarrier();
3593 void Wait();
3594 private:
3595 int num_threads_;
3596 int num_blocked_;
3597 v8::internal::Mutex* lock_;
3598 v8::internal::Semaphore* sem_;
3599 bool invalid_;
3600};
3601
3602ThreadBarrier::ThreadBarrier(int num_threads)
3603 : num_threads_(num_threads), num_blocked_(0) {
3604 lock_ = OS::CreateMutex();
3605 sem_ = OS::CreateSemaphore(0);
3606 invalid_ = false; // A barrier may only be used once. Then it is invalid.
3607}
3608
3609// Do not call, due to race condition with Wait().
3610// Could be resolved with Pthread condition variables.
3611ThreadBarrier::~ThreadBarrier() {
3612 lock_->Lock();
3613 delete lock_;
3614 delete sem_;
3615}
3616
3617void ThreadBarrier::Wait() {
3618 lock_->Lock();
3619 CHECK(!invalid_);
3620 if (num_blocked_ == num_threads_ - 1) {
3621 // Signal and unblock all waiting threads.
3622 for (int i = 0; i < num_threads_ - 1; ++i) {
3623 sem_->Signal();
3624 }
3625 invalid_ = true;
3626 printf("BARRIER\n\n");
3627 fflush(stdout);
3628 lock_->Unlock();
3629 } else { // Wait for the semaphore.
3630 ++num_blocked_;
3631 lock_->Unlock(); // Potential race condition with destructor because
3632 sem_->Wait(); // these two lines are not atomic.
3633 }
3634}
3635
3636// A set containing enough barriers and semaphores for any of the tests.
3637class Barriers {
3638 public:
3639 Barriers();
3640 void Initialize();
3641 ThreadBarrier barrier_1;
3642 ThreadBarrier barrier_2;
3643 ThreadBarrier barrier_3;
3644 ThreadBarrier barrier_4;
3645 ThreadBarrier barrier_5;
3646 v8::internal::Semaphore* semaphore_1;
3647 v8::internal::Semaphore* semaphore_2;
3648};
3649
3650Barriers::Barriers() : barrier_1(2), barrier_2(2),
3651 barrier_3(2), barrier_4(2), barrier_5(2) {}
3652
3653void Barriers::Initialize() {
3654 semaphore_1 = OS::CreateSemaphore(0);
3655 semaphore_2 = OS::CreateSemaphore(0);
3656}
3657
3658
3659// We match parts of the message to decide if it is a break message.
3660bool IsBreakEventMessage(char *message) {
3661 const char* type_event = "\"type\":\"event\"";
3662 const char* event_break = "\"event\":\"break\"";
3663 // Does the message contain both type:event and event:break?
3664 return strstr(message, type_event) != NULL &&
3665 strstr(message, event_break) != NULL;
3666}
3667
3668
Steve Block3ce2e202009-11-05 08:53:23 +00003669// We match parts of the message to decide if it is a exception message.
3670bool IsExceptionEventMessage(char *message) {
3671 const char* type_event = "\"type\":\"event\"";
3672 const char* event_exception = "\"event\":\"exception\"";
3673 // Does the message contain both type:event and event:exception?
3674 return strstr(message, type_event) != NULL &&
3675 strstr(message, event_exception) != NULL;
3676}
3677
3678
3679// We match the message wether it is an evaluate response message.
3680bool IsEvaluateResponseMessage(char* message) {
3681 const char* type_response = "\"type\":\"response\"";
3682 const char* command_evaluate = "\"command\":\"evaluate\"";
3683 // Does the message contain both type:response and command:evaluate?
3684 return strstr(message, type_response) != NULL &&
3685 strstr(message, command_evaluate) != NULL;
3686}
3687
3688
3689// We match parts of the message to get evaluate result int value.
3690int GetEvaluateIntResult(char *message) {
3691 const char* value = "\"value\":";
3692 char* pos = strstr(message, value);
3693 if (pos == NULL) {
3694 return -1;
3695 }
3696 int res = -1;
3697 res = atoi(pos + strlen(value));
3698 return res;
3699}
3700
3701
3702// We match parts of the message to get hit breakpoint id.
3703int GetBreakpointIdFromBreakEventMessage(char *message) {
3704 const char* breakpoints = "\"breakpoints\":[";
3705 char* pos = strstr(message, breakpoints);
3706 if (pos == NULL) {
3707 return -1;
3708 }
3709 int res = -1;
3710 res = atoi(pos + strlen(breakpoints));
3711 return res;
3712}
3713
3714
Steve Blocka7e24c12009-10-30 11:49:00 +00003715/* Test MessageQueues */
3716/* Tests the message queues that hold debugger commands and
3717 * response messages to the debugger. Fills queues and makes
3718 * them grow.
3719 */
3720Barriers message_queue_barriers;
3721
3722// This is the debugger thread, that executes no v8 calls except
3723// placing JSON debugger commands in the queue.
3724class MessageQueueDebuggerThread : public v8::internal::Thread {
3725 public:
3726 void Run();
3727};
3728
3729static void MessageHandler(const uint16_t* message, int length,
3730 v8::Debug::ClientData* client_data) {
3731 static char print_buffer[1000];
3732 Utf16ToAscii(message, length, print_buffer);
3733 if (IsBreakEventMessage(print_buffer)) {
3734 // Lets test script wait until break occurs to send commands.
3735 // Signals when a break is reported.
3736 message_queue_barriers.semaphore_2->Signal();
3737 }
3738
3739 // Allow message handler to block on a semaphore, to test queueing of
3740 // messages while blocked.
3741 message_queue_barriers.semaphore_1->Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +00003742}
3743
3744void MessageQueueDebuggerThread::Run() {
3745 const int kBufferSize = 1000;
3746 uint16_t buffer_1[kBufferSize];
3747 uint16_t buffer_2[kBufferSize];
3748 const char* command_1 =
3749 "{\"seq\":117,"
3750 "\"type\":\"request\","
3751 "\"command\":\"evaluate\","
3752 "\"arguments\":{\"expression\":\"1+2\"}}";
3753 const char* command_2 =
3754 "{\"seq\":118,"
3755 "\"type\":\"request\","
3756 "\"command\":\"evaluate\","
3757 "\"arguments\":{\"expression\":\"1+a\"}}";
3758 const char* command_3 =
3759 "{\"seq\":119,"
3760 "\"type\":\"request\","
3761 "\"command\":\"evaluate\","
3762 "\"arguments\":{\"expression\":\"c.d * b\"}}";
3763 const char* command_continue =
3764 "{\"seq\":106,"
3765 "\"type\":\"request\","
3766 "\"command\":\"continue\"}";
3767 const char* command_single_step =
3768 "{\"seq\":107,"
3769 "\"type\":\"request\","
3770 "\"command\":\"continue\","
3771 "\"arguments\":{\"stepaction\":\"next\"}}";
3772
3773 /* Interleaved sequence of actions by the two threads:*/
3774 // Main thread compiles and runs source_1
3775 message_queue_barriers.semaphore_1->Signal();
3776 message_queue_barriers.barrier_1.Wait();
3777 // Post 6 commands, filling the command queue and making it expand.
3778 // These calls return immediately, but the commands stay on the queue
3779 // until the execution of source_2.
3780 // Note: AsciiToUtf16 executes before SendCommand, so command is copied
3781 // to buffer before buffer is sent to SendCommand.
3782 v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_1, buffer_1));
3783 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_2, buffer_2));
3784 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
3785 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
3786 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
3787 message_queue_barriers.barrier_2.Wait();
3788 // Main thread compiles and runs source_2.
3789 // Queued commands are executed at the start of compilation of source_2(
3790 // beforeCompile event).
3791 // Free the message handler to process all the messages from the queue. 7
3792 // messages are expected: 2 afterCompile events and 5 responses.
3793 // All the commands added so far will fail to execute as long as call stack
3794 // is empty on beforeCompile event.
3795 for (int i = 0; i < 6 ; ++i) {
3796 message_queue_barriers.semaphore_1->Signal();
3797 }
3798 message_queue_barriers.barrier_3.Wait();
3799 // Main thread compiles and runs source_3.
3800 // Don't stop in the afterCompile handler.
3801 message_queue_barriers.semaphore_1->Signal();
3802 // source_3 includes a debugger statement, which causes a break event.
3803 // Wait on break event from hitting "debugger" statement
3804 message_queue_barriers.semaphore_2->Wait();
3805 // These should execute after the "debugger" statement in source_2
3806 v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_1, buffer_1));
3807 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_2, buffer_2));
3808 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
3809 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_single_step, buffer_2));
3810 // Run after 2 break events, 4 responses.
3811 for (int i = 0; i < 6 ; ++i) {
3812 message_queue_barriers.semaphore_1->Signal();
3813 }
3814 // Wait on break event after a single step executes.
3815 message_queue_barriers.semaphore_2->Wait();
3816 v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_2, buffer_1));
3817 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_continue, buffer_2));
3818 // Run after 2 responses.
3819 for (int i = 0; i < 2 ; ++i) {
3820 message_queue_barriers.semaphore_1->Signal();
3821 }
3822 // Main thread continues running source_3 to end, waits for this thread.
3823}
3824
3825MessageQueueDebuggerThread message_queue_debugger_thread;
3826
3827// This thread runs the v8 engine.
3828TEST(MessageQueues) {
3829 // Create a V8 environment
3830 v8::HandleScope scope;
3831 DebugLocalContext env;
3832 message_queue_barriers.Initialize();
3833 v8::Debug::SetMessageHandler(MessageHandler);
3834 message_queue_debugger_thread.Start();
3835
3836 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
3837 const char* source_2 = "e = 17;";
3838 const char* source_3 = "a = 4; debugger; a = 5; a = 6; a = 7;";
3839
3840 // See MessageQueueDebuggerThread::Run for interleaved sequence of
3841 // API calls and events in the two threads.
3842 CompileRun(source_1);
3843 message_queue_barriers.barrier_1.Wait();
3844 message_queue_barriers.barrier_2.Wait();
3845 CompileRun(source_2);
3846 message_queue_barriers.barrier_3.Wait();
3847 CompileRun(source_3);
3848 message_queue_debugger_thread.Join();
3849 fflush(stdout);
3850}
3851
3852
3853class TestClientData : public v8::Debug::ClientData {
3854 public:
3855 TestClientData() {
3856 constructor_call_counter++;
3857 }
3858 virtual ~TestClientData() {
3859 destructor_call_counter++;
3860 }
3861
3862 static void ResetCounters() {
3863 constructor_call_counter = 0;
3864 destructor_call_counter = 0;
3865 }
3866
3867 static int constructor_call_counter;
3868 static int destructor_call_counter;
3869};
3870
3871int TestClientData::constructor_call_counter = 0;
3872int TestClientData::destructor_call_counter = 0;
3873
3874
3875// Tests that MessageQueue doesn't destroy client data when expands and
3876// does destroy when it dies.
3877TEST(MessageQueueExpandAndDestroy) {
3878 TestClientData::ResetCounters();
3879 { // Create a scope for the queue.
3880 CommandMessageQueue queue(1);
3881 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
3882 new TestClientData()));
3883 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
3884 new TestClientData()));
3885 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
3886 new TestClientData()));
3887 CHECK_EQ(0, TestClientData::destructor_call_counter);
3888 queue.Get().Dispose();
3889 CHECK_EQ(1, TestClientData::destructor_call_counter);
3890 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
3891 new TestClientData()));
3892 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
3893 new TestClientData()));
3894 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
3895 new TestClientData()));
3896 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
3897 new TestClientData()));
3898 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
3899 new TestClientData()));
3900 CHECK_EQ(1, TestClientData::destructor_call_counter);
3901 queue.Get().Dispose();
3902 CHECK_EQ(2, TestClientData::destructor_call_counter);
3903 }
3904 // All the client data should be destroyed when the queue is destroyed.
3905 CHECK_EQ(TestClientData::destructor_call_counter,
3906 TestClientData::destructor_call_counter);
3907}
3908
3909
3910static int handled_client_data_instances_count = 0;
3911static void MessageHandlerCountingClientData(
3912 const v8::Debug::Message& message) {
3913 if (message.GetClientData() != NULL) {
3914 handled_client_data_instances_count++;
3915 }
3916}
3917
3918
3919// Tests that all client data passed to the debugger are sent to the handler.
3920TEST(SendClientDataToHandler) {
3921 // Create a V8 environment
3922 v8::HandleScope scope;
3923 DebugLocalContext env;
3924 TestClientData::ResetCounters();
3925 handled_client_data_instances_count = 0;
3926 v8::Debug::SetMessageHandler2(MessageHandlerCountingClientData);
3927 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
3928 const int kBufferSize = 1000;
3929 uint16_t buffer[kBufferSize];
3930 const char* command_1 =
3931 "{\"seq\":117,"
3932 "\"type\":\"request\","
3933 "\"command\":\"evaluate\","
3934 "\"arguments\":{\"expression\":\"1+2\"}}";
3935 const char* command_2 =
3936 "{\"seq\":118,"
3937 "\"type\":\"request\","
3938 "\"command\":\"evaluate\","
3939 "\"arguments\":{\"expression\":\"1+a\"}}";
3940 const char* command_continue =
3941 "{\"seq\":106,"
3942 "\"type\":\"request\","
3943 "\"command\":\"continue\"}";
3944
3945 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer),
3946 new TestClientData());
3947 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer), NULL);
3948 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer),
3949 new TestClientData());
3950 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer),
3951 new TestClientData());
3952 // All the messages will be processed on beforeCompile event.
3953 CompileRun(source_1);
3954 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer));
3955 CHECK_EQ(3, TestClientData::constructor_call_counter);
3956 CHECK_EQ(TestClientData::constructor_call_counter,
3957 handled_client_data_instances_count);
3958 CHECK_EQ(TestClientData::constructor_call_counter,
3959 TestClientData::destructor_call_counter);
3960}
3961
3962
3963/* Test ThreadedDebugging */
3964/* This test interrupts a running infinite loop that is
3965 * occupying the v8 thread by a break command from the
3966 * debugger thread. It then changes the value of a
3967 * global object, to make the loop terminate.
3968 */
3969
3970Barriers threaded_debugging_barriers;
3971
3972class V8Thread : public v8::internal::Thread {
3973 public:
3974 void Run();
3975};
3976
3977class DebuggerThread : public v8::internal::Thread {
3978 public:
3979 void Run();
3980};
3981
3982
3983static v8::Handle<v8::Value> ThreadedAtBarrier1(const v8::Arguments& args) {
3984 threaded_debugging_barriers.barrier_1.Wait();
3985 return v8::Undefined();
3986}
3987
3988
3989static void ThreadedMessageHandler(const v8::Debug::Message& message) {
3990 static char print_buffer[1000];
3991 v8::String::Value json(message.GetJSON());
3992 Utf16ToAscii(*json, json.length(), print_buffer);
3993 if (IsBreakEventMessage(print_buffer)) {
3994 threaded_debugging_barriers.barrier_2.Wait();
3995 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003996}
3997
3998
3999void V8Thread::Run() {
4000 const char* source =
4001 "flag = true;\n"
4002 "function bar( new_value ) {\n"
4003 " flag = new_value;\n"
4004 " return \"Return from bar(\" + new_value + \")\";\n"
4005 "}\n"
4006 "\n"
4007 "function foo() {\n"
4008 " var x = 1;\n"
4009 " while ( flag == true ) {\n"
4010 " if ( x == 1 ) {\n"
4011 " ThreadedAtBarrier1();\n"
4012 " }\n"
4013 " x = x + 1;\n"
4014 " }\n"
4015 "}\n"
4016 "\n"
4017 "foo();\n";
4018
4019 v8::HandleScope scope;
4020 DebugLocalContext env;
4021 v8::Debug::SetMessageHandler2(&ThreadedMessageHandler);
4022 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4023 global_template->Set(v8::String::New("ThreadedAtBarrier1"),
4024 v8::FunctionTemplate::New(ThreadedAtBarrier1));
4025 v8::Handle<v8::Context> context = v8::Context::New(NULL, global_template);
4026 v8::Context::Scope context_scope(context);
4027
4028 CompileRun(source);
4029}
4030
4031void DebuggerThread::Run() {
4032 const int kBufSize = 1000;
4033 uint16_t buffer[kBufSize];
4034
4035 const char* command_1 = "{\"seq\":102,"
4036 "\"type\":\"request\","
4037 "\"command\":\"evaluate\","
4038 "\"arguments\":{\"expression\":\"bar(false)\"}}";
4039 const char* command_2 = "{\"seq\":103,"
4040 "\"type\":\"request\","
4041 "\"command\":\"continue\"}";
4042
4043 threaded_debugging_barriers.barrier_1.Wait();
4044 v8::Debug::DebugBreak();
4045 threaded_debugging_barriers.barrier_2.Wait();
4046 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
4047 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
4048}
4049
4050DebuggerThread debugger_thread;
4051V8Thread v8_thread;
4052
4053TEST(ThreadedDebugging) {
4054 // Create a V8 environment
4055 threaded_debugging_barriers.Initialize();
4056
4057 v8_thread.Start();
4058 debugger_thread.Start();
4059
4060 v8_thread.Join();
4061 debugger_thread.Join();
4062}
4063
4064/* Test RecursiveBreakpoints */
4065/* In this test, the debugger evaluates a function with a breakpoint, after
4066 * hitting a breakpoint in another function. We do this with both values
4067 * of the flag enabling recursive breakpoints, and verify that the second
4068 * breakpoint is hit when enabled, and missed when disabled.
4069 */
4070
4071class BreakpointsV8Thread : public v8::internal::Thread {
4072 public:
4073 void Run();
4074};
4075
4076class BreakpointsDebuggerThread : public v8::internal::Thread {
4077 public:
4078 void Run();
4079};
4080
4081
4082Barriers* breakpoints_barriers;
Steve Block3ce2e202009-11-05 08:53:23 +00004083int break_event_breakpoint_id;
4084int evaluate_int_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00004085
4086static void BreakpointsMessageHandler(const v8::Debug::Message& message) {
4087 static char print_buffer[1000];
4088 v8::String::Value json(message.GetJSON());
4089 Utf16ToAscii(*json, json.length(), print_buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00004090
Steve Blocka7e24c12009-10-30 11:49:00 +00004091 if (IsBreakEventMessage(print_buffer)) {
Steve Block3ce2e202009-11-05 08:53:23 +00004092 break_event_breakpoint_id =
4093 GetBreakpointIdFromBreakEventMessage(print_buffer);
4094 breakpoints_barriers->semaphore_1->Signal();
4095 } else if (IsEvaluateResponseMessage(print_buffer)) {
4096 evaluate_int_result = GetEvaluateIntResult(print_buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00004097 breakpoints_barriers->semaphore_1->Signal();
4098 }
4099}
4100
4101
4102void BreakpointsV8Thread::Run() {
4103 const char* source_1 = "var y_global = 3;\n"
4104 "function cat( new_value ) {\n"
4105 " var x = new_value;\n"
Steve Block3ce2e202009-11-05 08:53:23 +00004106 " y_global = y_global + 4;\n"
Steve Blocka7e24c12009-10-30 11:49:00 +00004107 " x = 3 * x + 1;\n"
Steve Block3ce2e202009-11-05 08:53:23 +00004108 " y_global = y_global + 5;\n"
Steve Blocka7e24c12009-10-30 11:49:00 +00004109 " return x;\n"
4110 "}\n"
4111 "\n"
4112 "function dog() {\n"
4113 " var x = 1;\n"
4114 " x = y_global;"
4115 " var z = 3;"
4116 " x += 100;\n"
4117 " return x;\n"
4118 "}\n"
4119 "\n";
4120 const char* source_2 = "cat(17);\n"
4121 "cat(19);\n";
4122
4123 v8::HandleScope scope;
4124 DebugLocalContext env;
4125 v8::Debug::SetMessageHandler2(&BreakpointsMessageHandler);
4126
4127 CompileRun(source_1);
4128 breakpoints_barriers->barrier_1.Wait();
4129 breakpoints_barriers->barrier_2.Wait();
4130 CompileRun(source_2);
4131}
4132
4133
4134void BreakpointsDebuggerThread::Run() {
4135 const int kBufSize = 1000;
4136 uint16_t buffer[kBufSize];
4137
4138 const char* command_1 = "{\"seq\":101,"
4139 "\"type\":\"request\","
4140 "\"command\":\"setbreakpoint\","
4141 "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}";
4142 const char* command_2 = "{\"seq\":102,"
4143 "\"type\":\"request\","
4144 "\"command\":\"setbreakpoint\","
4145 "\"arguments\":{\"type\":\"function\",\"target\":\"dog\",\"line\":3}}";
Steve Block3ce2e202009-11-05 08:53:23 +00004146 const char* command_3 = "{\"seq\":103,"
Steve Blocka7e24c12009-10-30 11:49:00 +00004147 "\"type\":\"request\","
4148 "\"command\":\"evaluate\","
4149 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false}}";
Steve Block3ce2e202009-11-05 08:53:23 +00004150 const char* command_4 = "{\"seq\":104,"
Steve Blocka7e24c12009-10-30 11:49:00 +00004151 "\"type\":\"request\","
4152 "\"command\":\"evaluate\","
Steve Block3ce2e202009-11-05 08:53:23 +00004153 "\"arguments\":{\"expression\":\"x + 1\",\"disable_break\":true}}";
4154 const char* command_5 = "{\"seq\":105,"
Steve Blocka7e24c12009-10-30 11:49:00 +00004155 "\"type\":\"request\","
4156 "\"command\":\"continue\"}";
Steve Block3ce2e202009-11-05 08:53:23 +00004157 const char* command_6 = "{\"seq\":106,"
Steve Blocka7e24c12009-10-30 11:49:00 +00004158 "\"type\":\"request\","
4159 "\"command\":\"continue\"}";
Steve Block3ce2e202009-11-05 08:53:23 +00004160 const char* command_7 = "{\"seq\":107,"
Steve Blocka7e24c12009-10-30 11:49:00 +00004161 "\"type\":\"request\","
4162 "\"command\":\"evaluate\","
4163 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true}}";
Steve Block3ce2e202009-11-05 08:53:23 +00004164 const char* command_8 = "{\"seq\":108,"
Steve Blocka7e24c12009-10-30 11:49:00 +00004165 "\"type\":\"request\","
4166 "\"command\":\"continue\"}";
4167
4168
4169 // v8 thread initializes, runs source_1
4170 breakpoints_barriers->barrier_1.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00004171 // 1:Set breakpoint in cat() (will get id 1).
Steve Blocka7e24c12009-10-30 11:49:00 +00004172 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00004173 // 2:Set breakpoint in dog() (will get id 2).
Steve Blocka7e24c12009-10-30 11:49:00 +00004174 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
4175 breakpoints_barriers->barrier_2.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00004176 // V8 thread starts compiling source_2.
Steve Blocka7e24c12009-10-30 11:49:00 +00004177 // Automatic break happens, to run queued commands
4178 // breakpoints_barriers->semaphore_1->Wait();
4179 // Commands 1 through 3 run, thread continues.
4180 // v8 thread runs source_2 to breakpoint in cat().
4181 // message callback receives break event.
4182 breakpoints_barriers->semaphore_1->Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00004183 // Must have hit breakpoint #1.
4184 CHECK_EQ(1, break_event_breakpoint_id);
Steve Blocka7e24c12009-10-30 11:49:00 +00004185 // 4:Evaluate dog() (which has a breakpoint).
4186 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_3, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00004187 // V8 thread hits breakpoint in dog().
Steve Blocka7e24c12009-10-30 11:49:00 +00004188 breakpoints_barriers->semaphore_1->Wait(); // wait for break event
Steve Block3ce2e202009-11-05 08:53:23 +00004189 // Must have hit breakpoint #2.
4190 CHECK_EQ(2, break_event_breakpoint_id);
4191 // 5:Evaluate (x + 1).
Steve Blocka7e24c12009-10-30 11:49:00 +00004192 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_4, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00004193 // Evaluate (x + 1) finishes.
4194 breakpoints_barriers->semaphore_1->Wait();
4195 // Must have result 108.
4196 CHECK_EQ(108, evaluate_int_result);
4197 // 6:Continue evaluation of dog().
Steve Blocka7e24c12009-10-30 11:49:00 +00004198 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_5, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00004199 // Evaluate dog() finishes.
4200 breakpoints_barriers->semaphore_1->Wait();
4201 // Must have result 107.
4202 CHECK_EQ(107, evaluate_int_result);
Steve Blocka7e24c12009-10-30 11:49:00 +00004203 // 7:Continue evaluation of source_2, finish cat(17), hit breakpoint
4204 // in cat(19).
4205 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_6, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00004206 // Message callback gets break event.
Steve Blocka7e24c12009-10-30 11:49:00 +00004207 breakpoints_barriers->semaphore_1->Wait(); // wait for break event
Steve Block3ce2e202009-11-05 08:53:23 +00004208 // Must have hit breakpoint #1.
4209 CHECK_EQ(1, break_event_breakpoint_id);
4210 // 8: Evaluate dog() with breaks disabled.
Steve Blocka7e24c12009-10-30 11:49:00 +00004211 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_7, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00004212 // Evaluate dog() finishes.
4213 breakpoints_barriers->semaphore_1->Wait();
4214 // Must have result 116.
4215 CHECK_EQ(116, evaluate_int_result);
Steve Blocka7e24c12009-10-30 11:49:00 +00004216 // 9: Continue evaluation of source2, reach end.
4217 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_8, buffer));
4218}
4219
4220BreakpointsDebuggerThread breakpoints_debugger_thread;
4221BreakpointsV8Thread breakpoints_v8_thread;
4222
4223TEST(RecursiveBreakpoints) {
4224 i::FLAG_debugger_auto_break = true;
4225
4226 // Create a V8 environment
4227 Barriers stack_allocated_breakpoints_barriers;
4228 stack_allocated_breakpoints_barriers.Initialize();
4229 breakpoints_barriers = &stack_allocated_breakpoints_barriers;
4230
4231 breakpoints_v8_thread.Start();
4232 breakpoints_debugger_thread.Start();
4233
4234 breakpoints_v8_thread.Join();
4235 breakpoints_debugger_thread.Join();
4236}
4237
4238
4239static void DummyDebugEventListener(v8::DebugEvent event,
4240 v8::Handle<v8::Object> exec_state,
4241 v8::Handle<v8::Object> event_data,
4242 v8::Handle<v8::Value> data) {
4243}
4244
4245
4246TEST(SetDebugEventListenerOnUninitializedVM) {
4247 v8::Debug::SetDebugEventListener(DummyDebugEventListener);
4248}
4249
4250
4251static void DummyMessageHandler(const v8::Debug::Message& message) {
4252}
4253
4254
4255TEST(SetMessageHandlerOnUninitializedVM) {
4256 v8::Debug::SetMessageHandler2(DummyMessageHandler);
4257}
4258
4259
4260TEST(DebugBreakOnUninitializedVM) {
4261 v8::Debug::DebugBreak();
4262}
4263
4264
4265TEST(SendCommandToUninitializedVM) {
4266 const char* dummy_command = "{}";
4267 uint16_t dummy_buffer[80];
4268 int dummy_length = AsciiToUtf16(dummy_command, dummy_buffer);
4269 v8::Debug::SendCommand(dummy_buffer, dummy_length);
4270}
4271
4272
4273// Source for a JavaScript function which returns the data parameter of a
4274// function called in the context of the debugger. If no data parameter is
4275// passed it throws an exception.
4276static const char* debugger_call_with_data_source =
4277 "function debugger_call_with_data(exec_state, data) {"
4278 " if (data) return data;"
4279 " throw 'No data!'"
4280 "}";
4281v8::Handle<v8::Function> debugger_call_with_data;
4282
4283
4284// Source for a JavaScript function which returns the data parameter of a
4285// function called in the context of the debugger. If no data parameter is
4286// passed it throws an exception.
4287static const char* debugger_call_with_closure_source =
4288 "var x = 3;"
4289 "(function (exec_state) {"
4290 " if (exec_state.y) return x - 1;"
4291 " exec_state.y = x;"
4292 " return exec_state.y"
4293 "})";
4294v8::Handle<v8::Function> debugger_call_with_closure;
4295
4296// Function to retrieve the number of JavaScript frames by calling a JavaScript
4297// in the debugger.
4298static v8::Handle<v8::Value> CheckFrameCount(const v8::Arguments& args) {
4299 CHECK(v8::Debug::Call(frame_count)->IsNumber());
4300 CHECK_EQ(args[0]->Int32Value(),
4301 v8::Debug::Call(frame_count)->Int32Value());
4302 return v8::Undefined();
4303}
4304
4305
4306// Function to retrieve the source line of the top JavaScript frame by calling a
4307// JavaScript function in the debugger.
4308static v8::Handle<v8::Value> CheckSourceLine(const v8::Arguments& args) {
4309 CHECK(v8::Debug::Call(frame_source_line)->IsNumber());
4310 CHECK_EQ(args[0]->Int32Value(),
4311 v8::Debug::Call(frame_source_line)->Int32Value());
4312 return v8::Undefined();
4313}
4314
4315
4316// Function to test passing an additional parameter to a JavaScript function
4317// called in the debugger. It also tests that functions called in the debugger
4318// can throw exceptions.
4319static v8::Handle<v8::Value> CheckDataParameter(const v8::Arguments& args) {
4320 v8::Handle<v8::String> data = v8::String::New("Test");
4321 CHECK(v8::Debug::Call(debugger_call_with_data, data)->IsString());
4322
4323 CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
4324 CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
4325
4326 v8::TryCatch catcher;
4327 v8::Debug::Call(debugger_call_with_data);
4328 CHECK(catcher.HasCaught());
4329 CHECK(catcher.Exception()->IsString());
4330
4331 return v8::Undefined();
4332}
4333
4334
4335// Function to test using a JavaScript with closure in the debugger.
4336static v8::Handle<v8::Value> CheckClosure(const v8::Arguments& args) {
4337 CHECK(v8::Debug::Call(debugger_call_with_closure)->IsNumber());
4338 CHECK_EQ(3, v8::Debug::Call(debugger_call_with_closure)->Int32Value());
4339 return v8::Undefined();
4340}
4341
4342
4343// Test functions called through the debugger.
4344TEST(CallFunctionInDebugger) {
4345 // Create and enter a context with the functions CheckFrameCount,
4346 // CheckSourceLine and CheckDataParameter installed.
4347 v8::HandleScope scope;
4348 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4349 global_template->Set(v8::String::New("CheckFrameCount"),
4350 v8::FunctionTemplate::New(CheckFrameCount));
4351 global_template->Set(v8::String::New("CheckSourceLine"),
4352 v8::FunctionTemplate::New(CheckSourceLine));
4353 global_template->Set(v8::String::New("CheckDataParameter"),
4354 v8::FunctionTemplate::New(CheckDataParameter));
4355 global_template->Set(v8::String::New("CheckClosure"),
4356 v8::FunctionTemplate::New(CheckClosure));
4357 v8::Handle<v8::Context> context = v8::Context::New(NULL, global_template);
4358 v8::Context::Scope context_scope(context);
4359
4360 // Compile a function for checking the number of JavaScript frames.
4361 v8::Script::Compile(v8::String::New(frame_count_source))->Run();
4362 frame_count = v8::Local<v8::Function>::Cast(
4363 context->Global()->Get(v8::String::New("frame_count")));
4364
4365 // Compile a function for returning the source line for the top frame.
4366 v8::Script::Compile(v8::String::New(frame_source_line_source))->Run();
4367 frame_source_line = v8::Local<v8::Function>::Cast(
4368 context->Global()->Get(v8::String::New("frame_source_line")));
4369
4370 // Compile a function returning the data parameter.
4371 v8::Script::Compile(v8::String::New(debugger_call_with_data_source))->Run();
4372 debugger_call_with_data = v8::Local<v8::Function>::Cast(
4373 context->Global()->Get(v8::String::New("debugger_call_with_data")));
4374
4375 // Compile a function capturing closure.
4376 debugger_call_with_closure = v8::Local<v8::Function>::Cast(
4377 v8::Script::Compile(
4378 v8::String::New(debugger_call_with_closure_source))->Run());
4379
4380 // Calling a function through the debugger returns undefined if there are no
4381 // JavaScript frames.
4382 CHECK(v8::Debug::Call(frame_count)->IsUndefined());
4383 CHECK(v8::Debug::Call(frame_source_line)->IsUndefined());
4384 CHECK(v8::Debug::Call(debugger_call_with_data)->IsUndefined());
4385
4386 // Test that the number of frames can be retrieved.
4387 v8::Script::Compile(v8::String::New("CheckFrameCount(1)"))->Run();
4388 v8::Script::Compile(v8::String::New("function f() {"
4389 " CheckFrameCount(2);"
4390 "}; f()"))->Run();
4391
4392 // Test that the source line can be retrieved.
4393 v8::Script::Compile(v8::String::New("CheckSourceLine(0)"))->Run();
4394 v8::Script::Compile(v8::String::New("function f() {\n"
4395 " CheckSourceLine(1)\n"
4396 " CheckSourceLine(2)\n"
4397 " CheckSourceLine(3)\n"
4398 "}; f()"))->Run();
4399
4400 // Test that a parameter can be passed to a function called in the debugger.
4401 v8::Script::Compile(v8::String::New("CheckDataParameter()"))->Run();
4402
4403 // Test that a function with closure can be run in the debugger.
4404 v8::Script::Compile(v8::String::New("CheckClosure()"))->Run();
4405
4406
4407 // Test that the source line is correct when there is a line offset.
4408 v8::ScriptOrigin origin(v8::String::New("test"),
4409 v8::Integer::New(7));
4410 v8::Script::Compile(v8::String::New("CheckSourceLine(7)"), &origin)->Run();
4411 v8::Script::Compile(v8::String::New("function f() {\n"
4412 " CheckSourceLine(8)\n"
4413 " CheckSourceLine(9)\n"
4414 " CheckSourceLine(10)\n"
4415 "}; f()"), &origin)->Run();
4416}
4417
4418
4419// Debugger message handler which counts the number of breaks.
4420static void SendContinueCommand();
4421static void MessageHandlerBreakPointHitCount(
4422 const v8::Debug::Message& message) {
4423 if (message.IsEvent() && message.GetEvent() == v8::Break) {
4424 // Count the number of breaks.
4425 break_point_hit_count++;
4426
4427 SendContinueCommand();
4428 }
4429}
4430
4431
4432// Test that clearing the debug event listener actually clears all break points
4433// and related information.
4434TEST(DebuggerUnload) {
4435 DebugLocalContext env;
4436
4437 // Check debugger is unloaded before it is used.
4438 CheckDebuggerUnloaded();
4439
4440 // Set a debug event listener.
4441 break_point_hit_count = 0;
4442 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
4443 v8::Undefined());
4444 {
4445 v8::HandleScope scope;
4446 // Create a couple of functions for the test.
4447 v8::Local<v8::Function> foo =
4448 CompileFunction(&env, "function foo(){x=1}", "foo");
4449 v8::Local<v8::Function> bar =
4450 CompileFunction(&env, "function bar(){y=2}", "bar");
4451
4452 // Set some break points.
4453 SetBreakPoint(foo, 0);
4454 SetBreakPoint(foo, 4);
4455 SetBreakPoint(bar, 0);
4456 SetBreakPoint(bar, 4);
4457
4458 // Make sure that the break points are there.
4459 break_point_hit_count = 0;
4460 foo->Call(env->Global(), 0, NULL);
4461 CHECK_EQ(2, break_point_hit_count);
4462 bar->Call(env->Global(), 0, NULL);
4463 CHECK_EQ(4, break_point_hit_count);
4464 }
4465
4466 // Remove the debug event listener without clearing breakpoints. Do this
4467 // outside a handle scope.
4468 v8::Debug::SetDebugEventListener(NULL);
4469 CheckDebuggerUnloaded(true);
4470
4471 // Now set a debug message handler.
4472 break_point_hit_count = 0;
4473 v8::Debug::SetMessageHandler2(MessageHandlerBreakPointHitCount);
4474 {
4475 v8::HandleScope scope;
4476
4477 // Get the test functions again.
4478 v8::Local<v8::Function> foo =
4479 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
4480 v8::Local<v8::Function> bar =
4481 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
4482
4483 foo->Call(env->Global(), 0, NULL);
4484 CHECK_EQ(0, break_point_hit_count);
4485
4486 // Set break points and run again.
4487 SetBreakPoint(foo, 0);
4488 SetBreakPoint(foo, 4);
4489 foo->Call(env->Global(), 0, NULL);
4490 CHECK_EQ(2, break_point_hit_count);
4491 }
4492
4493 // Remove the debug message handler without clearing breakpoints. Do this
4494 // outside a handle scope.
4495 v8::Debug::SetMessageHandler2(NULL);
4496 CheckDebuggerUnloaded(true);
4497}
4498
4499
4500// Sends continue command to the debugger.
4501static void SendContinueCommand() {
4502 const int kBufferSize = 1000;
4503 uint16_t buffer[kBufferSize];
4504 const char* command_continue =
4505 "{\"seq\":0,"
4506 "\"type\":\"request\","
4507 "\"command\":\"continue\"}";
4508
4509 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer));
4510}
4511
4512
4513// Debugger message handler which counts the number of times it is called.
4514static int message_handler_hit_count = 0;
4515static void MessageHandlerHitCount(const v8::Debug::Message& message) {
4516 message_handler_hit_count++;
4517
Steve Block3ce2e202009-11-05 08:53:23 +00004518 static char print_buffer[1000];
4519 v8::String::Value json(message.GetJSON());
4520 Utf16ToAscii(*json, json.length(), print_buffer);
4521 if (IsExceptionEventMessage(print_buffer)) {
4522 // Send a continue command for exception events.
4523 SendContinueCommand();
4524 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004525}
4526
4527
4528// Test clearing the debug message handler.
4529TEST(DebuggerClearMessageHandler) {
4530 v8::HandleScope scope;
4531 DebugLocalContext env;
4532
4533 // Check debugger is unloaded before it is used.
4534 CheckDebuggerUnloaded();
4535
4536 // Set a debug message handler.
4537 v8::Debug::SetMessageHandler2(MessageHandlerHitCount);
4538
4539 // Run code to throw a unhandled exception. This should end up in the message
4540 // handler.
4541 CompileRun("throw 1");
4542
4543 // The message handler should be called.
4544 CHECK_GT(message_handler_hit_count, 0);
4545
4546 // Clear debug message handler.
4547 message_handler_hit_count = 0;
4548 v8::Debug::SetMessageHandler(NULL);
4549
4550 // Run code to throw a unhandled exception. This should end up in the message
4551 // handler.
4552 CompileRun("throw 1");
4553
4554 // The message handler should not be called more.
4555 CHECK_EQ(0, message_handler_hit_count);
4556
4557 CheckDebuggerUnloaded(true);
4558}
4559
4560
4561// Debugger message handler which clears the message handler while active.
4562static void MessageHandlerClearingMessageHandler(
4563 const v8::Debug::Message& message) {
4564 message_handler_hit_count++;
4565
4566 // Clear debug message handler.
4567 v8::Debug::SetMessageHandler(NULL);
4568}
4569
4570
4571// Test clearing the debug message handler while processing a debug event.
4572TEST(DebuggerClearMessageHandlerWhileActive) {
4573 v8::HandleScope scope;
4574 DebugLocalContext env;
4575
4576 // Check debugger is unloaded before it is used.
4577 CheckDebuggerUnloaded();
4578
4579 // Set a debug message handler.
4580 v8::Debug::SetMessageHandler2(MessageHandlerClearingMessageHandler);
4581
4582 // Run code to throw a unhandled exception. This should end up in the message
4583 // handler.
4584 CompileRun("throw 1");
4585
4586 // The message handler should be called.
4587 CHECK_EQ(1, message_handler_hit_count);
4588
4589 CheckDebuggerUnloaded(true);
4590}
4591
4592
4593/* Test DebuggerHostDispatch */
4594/* In this test, the debugger waits for a command on a breakpoint
4595 * and is dispatching host commands while in the infinite loop.
4596 */
4597
4598class HostDispatchV8Thread : public v8::internal::Thread {
4599 public:
4600 void Run();
4601};
4602
4603class HostDispatchDebuggerThread : public v8::internal::Thread {
4604 public:
4605 void Run();
4606};
4607
4608Barriers* host_dispatch_barriers;
4609
4610static void HostDispatchMessageHandler(const v8::Debug::Message& message) {
4611 static char print_buffer[1000];
4612 v8::String::Value json(message.GetJSON());
4613 Utf16ToAscii(*json, json.length(), print_buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00004614}
4615
4616
4617static void HostDispatchDispatchHandler() {
4618 host_dispatch_barriers->semaphore_1->Signal();
4619}
4620
4621
4622void HostDispatchV8Thread::Run() {
4623 const char* source_1 = "var y_global = 3;\n"
4624 "function cat( new_value ) {\n"
4625 " var x = new_value;\n"
4626 " y_global = 4;\n"
4627 " x = 3 * x + 1;\n"
4628 " y_global = 5;\n"
4629 " return x;\n"
4630 "}\n"
4631 "\n";
4632 const char* source_2 = "cat(17);\n";
4633
4634 v8::HandleScope scope;
4635 DebugLocalContext env;
4636
4637 // Setup message and host dispatch handlers.
4638 v8::Debug::SetMessageHandler2(HostDispatchMessageHandler);
4639 v8::Debug::SetHostDispatchHandler(HostDispatchDispatchHandler, 10 /* ms */);
4640
4641 CompileRun(source_1);
4642 host_dispatch_barriers->barrier_1.Wait();
4643 host_dispatch_barriers->barrier_2.Wait();
4644 CompileRun(source_2);
4645}
4646
4647
4648void HostDispatchDebuggerThread::Run() {
4649 const int kBufSize = 1000;
4650 uint16_t buffer[kBufSize];
4651
4652 const char* command_1 = "{\"seq\":101,"
4653 "\"type\":\"request\","
4654 "\"command\":\"setbreakpoint\","
4655 "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}";
4656 const char* command_2 = "{\"seq\":102,"
4657 "\"type\":\"request\","
4658 "\"command\":\"continue\"}";
4659
4660 // v8 thread initializes, runs source_1
4661 host_dispatch_barriers->barrier_1.Wait();
4662 // 1: Set breakpoint in cat().
4663 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
4664
4665 host_dispatch_barriers->barrier_2.Wait();
4666 // v8 thread starts compiling source_2.
4667 // Break happens, to run queued commands and host dispatches.
4668 // Wait for host dispatch to be processed.
4669 host_dispatch_barriers->semaphore_1->Wait();
4670 // 2: Continue evaluation
4671 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
4672}
4673
4674HostDispatchDebuggerThread host_dispatch_debugger_thread;
4675HostDispatchV8Thread host_dispatch_v8_thread;
4676
4677
4678TEST(DebuggerHostDispatch) {
4679 i::FLAG_debugger_auto_break = true;
4680
4681 // Create a V8 environment
4682 Barriers stack_allocated_host_dispatch_barriers;
4683 stack_allocated_host_dispatch_barriers.Initialize();
4684 host_dispatch_barriers = &stack_allocated_host_dispatch_barriers;
4685
4686 host_dispatch_v8_thread.Start();
4687 host_dispatch_debugger_thread.Start();
4688
4689 host_dispatch_v8_thread.Join();
4690 host_dispatch_debugger_thread.Join();
4691}
4692
4693
Steve Blockd0582a62009-12-15 09:54:21 +00004694/* Test DebugMessageDispatch */
4695/* In this test, the V8 thread waits for a message from the debug thread.
4696 * The DebugMessageDispatchHandler is executed from the debugger thread
4697 * which signals the V8 thread to wake up.
4698 */
4699
4700class DebugMessageDispatchV8Thread : public v8::internal::Thread {
4701 public:
4702 void Run();
4703};
4704
4705class DebugMessageDispatchDebuggerThread : public v8::internal::Thread {
4706 public:
4707 void Run();
4708};
4709
4710Barriers* debug_message_dispatch_barriers;
4711
4712
4713static void DebugMessageHandler() {
4714 debug_message_dispatch_barriers->semaphore_1->Signal();
4715}
4716
4717
4718void DebugMessageDispatchV8Thread::Run() {
4719 v8::HandleScope scope;
4720 DebugLocalContext env;
4721
4722 // Setup debug message dispatch handler.
4723 v8::Debug::SetDebugMessageDispatchHandler(DebugMessageHandler);
4724
4725 CompileRun("var y = 1 + 2;\n");
4726 debug_message_dispatch_barriers->barrier_1.Wait();
4727 debug_message_dispatch_barriers->semaphore_1->Wait();
4728 debug_message_dispatch_barriers->barrier_2.Wait();
4729}
4730
4731
4732void DebugMessageDispatchDebuggerThread::Run() {
4733 debug_message_dispatch_barriers->barrier_1.Wait();
4734 SendContinueCommand();
4735 debug_message_dispatch_barriers->barrier_2.Wait();
4736}
4737
4738DebugMessageDispatchDebuggerThread debug_message_dispatch_debugger_thread;
4739DebugMessageDispatchV8Thread debug_message_dispatch_v8_thread;
4740
4741
4742TEST(DebuggerDebugMessageDispatch) {
4743 i::FLAG_debugger_auto_break = true;
4744
4745 // Create a V8 environment
4746 Barriers stack_allocated_debug_message_dispatch_barriers;
4747 stack_allocated_debug_message_dispatch_barriers.Initialize();
4748 debug_message_dispatch_barriers =
4749 &stack_allocated_debug_message_dispatch_barriers;
4750
4751 debug_message_dispatch_v8_thread.Start();
4752 debug_message_dispatch_debugger_thread.Start();
4753
4754 debug_message_dispatch_v8_thread.Join();
4755 debug_message_dispatch_debugger_thread.Join();
4756}
4757
4758
Steve Blocka7e24c12009-10-30 11:49:00 +00004759TEST(DebuggerAgent) {
4760 // Make sure these ports is not used by other tests to allow tests to run in
4761 // parallel.
4762 const int kPort1 = 5858;
4763 const int kPort2 = 5857;
4764 const int kPort3 = 5856;
4765
4766 // Make a string with the port2 number.
4767 const int kPortBufferLen = 6;
4768 char port2_str[kPortBufferLen];
4769 OS::SNPrintF(i::Vector<char>(port2_str, kPortBufferLen), "%d", kPort2);
4770
4771 bool ok;
4772
4773 // Initialize the socket library.
4774 i::Socket::Setup();
4775
4776 // Test starting and stopping the agent without any client connection.
4777 i::Debugger::StartAgent("test", kPort1);
4778 i::Debugger::StopAgent();
4779
4780 // Test starting the agent, connecting a client and shutting down the agent
4781 // with the client connected.
4782 ok = i::Debugger::StartAgent("test", kPort2);
4783 CHECK(ok);
4784 i::Debugger::WaitForAgent();
4785 i::Socket* client = i::OS::CreateSocket();
4786 ok = client->Connect("localhost", port2_str);
4787 CHECK(ok);
4788 i::Debugger::StopAgent();
4789 delete client;
4790
4791 // Test starting and stopping the agent with the required port already
4792 // occoupied.
4793 i::Socket* server = i::OS::CreateSocket();
4794 server->Bind(kPort3);
4795
4796 i::Debugger::StartAgent("test", kPort3);
4797 i::Debugger::StopAgent();
4798
4799 delete server;
4800}
4801
4802
4803class DebuggerAgentProtocolServerThread : public i::Thread {
4804 public:
4805 explicit DebuggerAgentProtocolServerThread(int port)
4806 : port_(port), server_(NULL), client_(NULL),
4807 listening_(OS::CreateSemaphore(0)) {
4808 }
4809 ~DebuggerAgentProtocolServerThread() {
4810 // Close both sockets.
4811 delete client_;
4812 delete server_;
4813 delete listening_;
4814 }
4815
4816 void Run();
4817 void WaitForListening() { listening_->Wait(); }
4818 char* body() { return *body_; }
4819
4820 private:
4821 int port_;
4822 i::SmartPointer<char> body_;
4823 i::Socket* server_; // Server socket used for bind/accept.
4824 i::Socket* client_; // Single client connection used by the test.
4825 i::Semaphore* listening_; // Signalled when the server is in listen mode.
4826};
4827
4828
4829void DebuggerAgentProtocolServerThread::Run() {
4830 bool ok;
4831
4832 // Create the server socket and bind it to the requested port.
4833 server_ = i::OS::CreateSocket();
4834 CHECK(server_ != NULL);
4835 ok = server_->Bind(port_);
4836 CHECK(ok);
4837
4838 // Listen for new connections.
4839 ok = server_->Listen(1);
4840 CHECK(ok);
4841 listening_->Signal();
4842
4843 // Accept a connection.
4844 client_ = server_->Accept();
4845 CHECK(client_ != NULL);
4846
4847 // Receive a debugger agent protocol message.
4848 i::DebuggerAgentUtil::ReceiveMessage(client_);
4849}
4850
4851
4852TEST(DebuggerAgentProtocolOverflowHeader) {
4853 // Make sure this port is not used by other tests to allow tests to run in
4854 // parallel.
4855 const int kPort = 5860;
4856 static const char* kLocalhost = "localhost";
4857
4858 // Make a string with the port number.
4859 const int kPortBufferLen = 6;
4860 char port_str[kPortBufferLen];
4861 OS::SNPrintF(i::Vector<char>(port_str, kPortBufferLen), "%d", kPort);
4862
4863 // Initialize the socket library.
4864 i::Socket::Setup();
4865
4866 // Create a socket server to receive a debugger agent message.
4867 DebuggerAgentProtocolServerThread* server =
4868 new DebuggerAgentProtocolServerThread(kPort);
4869 server->Start();
4870 server->WaitForListening();
4871
4872 // Connect.
4873 i::Socket* client = i::OS::CreateSocket();
4874 CHECK(client != NULL);
4875 bool ok = client->Connect(kLocalhost, port_str);
4876 CHECK(ok);
4877
4878 // Send headers which overflow the receive buffer.
4879 static const int kBufferSize = 1000;
4880 char buffer[kBufferSize];
4881
4882 // Long key and short value: XXXX....XXXX:0\r\n.
4883 for (int i = 0; i < kBufferSize - 4; i++) {
4884 buffer[i] = 'X';
4885 }
4886 buffer[kBufferSize - 4] = ':';
4887 buffer[kBufferSize - 3] = '0';
4888 buffer[kBufferSize - 2] = '\r';
4889 buffer[kBufferSize - 1] = '\n';
4890 client->Send(buffer, kBufferSize);
4891
4892 // Short key and long value: X:XXXX....XXXX\r\n.
4893 buffer[0] = 'X';
4894 buffer[1] = ':';
4895 for (int i = 2; i < kBufferSize - 2; i++) {
4896 buffer[i] = 'X';
4897 }
4898 buffer[kBufferSize - 2] = '\r';
4899 buffer[kBufferSize - 1] = '\n';
4900 client->Send(buffer, kBufferSize);
4901
4902 // Add empty body to request.
4903 const char* content_length_zero_header = "Content-Length:0\r\n";
Steve Blockd0582a62009-12-15 09:54:21 +00004904 client->Send(content_length_zero_header,
4905 StrLength(content_length_zero_header));
Steve Blocka7e24c12009-10-30 11:49:00 +00004906 client->Send("\r\n", 2);
4907
4908 // Wait until data is received.
4909 server->Join();
4910
4911 // Check for empty body.
4912 CHECK(server->body() == NULL);
4913
4914 // Close the client before the server to avoid TIME_WAIT issues.
4915 client->Shutdown();
4916 delete client;
4917 delete server;
4918}
4919
4920
4921// Test for issue http://code.google.com/p/v8/issues/detail?id=289.
4922// Make sure that DebugGetLoadedScripts doesn't return scripts
4923// with disposed external source.
4924class EmptyExternalStringResource : public v8::String::ExternalStringResource {
4925 public:
4926 EmptyExternalStringResource() { empty_[0] = 0; }
4927 virtual ~EmptyExternalStringResource() {}
4928 virtual size_t length() const { return empty_.length(); }
4929 virtual const uint16_t* data() const { return empty_.start(); }
4930 private:
4931 ::v8::internal::EmbeddedVector<uint16_t, 1> empty_;
4932};
4933
4934
4935TEST(DebugGetLoadedScripts) {
4936 v8::HandleScope scope;
4937 DebugLocalContext env;
4938 env.ExposeDebug();
4939
4940 EmptyExternalStringResource source_ext_str;
4941 v8::Local<v8::String> source = v8::String::NewExternal(&source_ext_str);
4942 v8::Handle<v8::Script> evil_script = v8::Script::Compile(source);
4943 Handle<i::ExternalTwoByteString> i_source(
4944 i::ExternalTwoByteString::cast(*v8::Utils::OpenHandle(*source)));
4945 // This situation can happen if source was an external string disposed
4946 // by its owner.
4947 i_source->set_resource(0);
4948
4949 bool allow_natives_syntax = i::FLAG_allow_natives_syntax;
4950 i::FLAG_allow_natives_syntax = true;
4951 CompileRun(
4952 "var scripts = %DebugGetLoadedScripts();"
4953 "var count = scripts.length;"
4954 "for (var i = 0; i < count; ++i) {"
4955 " scripts[i].line_ends;"
4956 "}");
4957 // Must not crash while accessing line_ends.
4958 i::FLAG_allow_natives_syntax = allow_natives_syntax;
4959
4960 // Some scripts are retrieved - at least the number of native scripts.
4961 CHECK_GT((*env)->Global()->Get(v8::String::New("count"))->Int32Value(), 8);
4962}
4963
4964
4965// Test script break points set on lines.
4966TEST(ScriptNameAndData) {
4967 v8::HandleScope scope;
4968 DebugLocalContext env;
4969 env.ExposeDebug();
4970
4971 // Create functions for retrieving script name and data for the function on
4972 // the top frame when hitting a break point.
4973 frame_script_name = CompileFunction(&env,
4974 frame_script_name_source,
4975 "frame_script_name");
4976 frame_script_data = CompileFunction(&env,
4977 frame_script_data_source,
4978 "frame_script_data");
4979
4980 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
4981 v8::Undefined());
4982
4983 // Test function source.
4984 v8::Local<v8::String> script = v8::String::New(
4985 "function f() {\n"
4986 " debugger;\n"
4987 "}\n");
4988
4989 v8::ScriptOrigin origin1 = v8::ScriptOrigin(v8::String::New("name"));
4990 v8::Handle<v8::Script> script1 = v8::Script::Compile(script, &origin1);
4991 script1->SetData(v8::String::New("data"));
4992 script1->Run();
4993 v8::Local<v8::Function> f;
4994 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
4995
4996 f->Call(env->Global(), 0, NULL);
4997 CHECK_EQ(1, break_point_hit_count);
4998 CHECK_EQ("name", last_script_name_hit);
4999 CHECK_EQ("data", last_script_data_hit);
5000
5001 // Compile the same script again without setting data. As the compilation
5002 // cache is disabled when debugging expect the data to be missing.
5003 v8::Script::Compile(script, &origin1)->Run();
5004 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
5005 f->Call(env->Global(), 0, NULL);
5006 CHECK_EQ(2, break_point_hit_count);
5007 CHECK_EQ("name", last_script_name_hit);
5008 CHECK_EQ("", last_script_data_hit); // Undefined results in empty string.
5009
5010 v8::Local<v8::String> data_obj_source = v8::String::New(
5011 "({ a: 'abc',\n"
5012 " b: 123,\n"
5013 " toString: function() { return this.a + ' ' + this.b; }\n"
5014 "})\n");
5015 v8::Local<v8::Value> data_obj = v8::Script::Compile(data_obj_source)->Run();
5016 v8::ScriptOrigin origin2 = v8::ScriptOrigin(v8::String::New("new name"));
5017 v8::Handle<v8::Script> script2 = v8::Script::Compile(script, &origin2);
5018 script2->Run();
Steve Blockd0582a62009-12-15 09:54:21 +00005019 script2->SetData(data_obj->ToString());
Steve Blocka7e24c12009-10-30 11:49:00 +00005020 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
5021 f->Call(env->Global(), 0, NULL);
5022 CHECK_EQ(3, break_point_hit_count);
5023 CHECK_EQ("new name", last_script_name_hit);
5024 CHECK_EQ("abc 123", last_script_data_hit);
5025}
5026
5027
5028static v8::Persistent<v8::Context> expected_context;
5029static v8::Handle<v8::Value> expected_context_data;
5030
5031
5032// Check that the expected context is the one generating the debug event.
5033static void ContextCheckMessageHandler(const v8::Debug::Message& message) {
5034 CHECK(message.GetEventContext() == expected_context);
5035 CHECK(message.GetEventContext()->GetData()->StrictEquals(
5036 expected_context_data));
5037 message_handler_hit_count++;
5038
Steve Block3ce2e202009-11-05 08:53:23 +00005039 static char print_buffer[1000];
5040 v8::String::Value json(message.GetJSON());
5041 Utf16ToAscii(*json, json.length(), print_buffer);
5042
Steve Blocka7e24c12009-10-30 11:49:00 +00005043 // Send a continue command for break events.
Steve Block3ce2e202009-11-05 08:53:23 +00005044 if (IsBreakEventMessage(print_buffer)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005045 SendContinueCommand();
5046 }
5047}
5048
5049
5050// Test which creates two contexts and sets different embedder data on each.
5051// Checks that this data is set correctly and that when the debug message
5052// handler is called the expected context is the one active.
5053TEST(ContextData) {
5054 v8::HandleScope scope;
5055
5056 v8::Debug::SetMessageHandler2(ContextCheckMessageHandler);
5057
5058 // Create two contexts.
5059 v8::Persistent<v8::Context> context_1;
5060 v8::Persistent<v8::Context> context_2;
5061 v8::Handle<v8::ObjectTemplate> global_template =
5062 v8::Handle<v8::ObjectTemplate>();
5063 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>();
5064 context_1 = v8::Context::New(NULL, global_template, global_object);
5065 context_2 = v8::Context::New(NULL, global_template, global_object);
5066
5067 // Default data value is undefined.
5068 CHECK(context_1->GetData()->IsUndefined());
5069 CHECK(context_2->GetData()->IsUndefined());
5070
5071 // Set and check different data values.
Steve Blockd0582a62009-12-15 09:54:21 +00005072 v8::Handle<v8::String> data_1 = v8::String::New("1");
5073 v8::Handle<v8::String> data_2 = v8::String::New("2");
Steve Blocka7e24c12009-10-30 11:49:00 +00005074 context_1->SetData(data_1);
5075 context_2->SetData(data_2);
5076 CHECK(context_1->GetData()->StrictEquals(data_1));
5077 CHECK(context_2->GetData()->StrictEquals(data_2));
5078
5079 // Simple test function which causes a break.
5080 const char* source = "function f() { debugger; }";
5081
5082 // Enter and run function in the first context.
5083 {
5084 v8::Context::Scope context_scope(context_1);
5085 expected_context = context_1;
5086 expected_context_data = data_1;
5087 v8::Local<v8::Function> f = CompileFunction(source, "f");
5088 f->Call(context_1->Global(), 0, NULL);
5089 }
5090
5091
5092 // Enter and run function in the second context.
5093 {
5094 v8::Context::Scope context_scope(context_2);
5095 expected_context = context_2;
5096 expected_context_data = data_2;
5097 v8::Local<v8::Function> f = CompileFunction(source, "f");
5098 f->Call(context_2->Global(), 0, NULL);
5099 }
5100
5101 // Two times compile event and two times break event.
5102 CHECK_GT(message_handler_hit_count, 4);
5103
5104 v8::Debug::SetMessageHandler2(NULL);
5105 CheckDebuggerUnloaded();
5106}
5107
5108
5109// Debug message handler which issues a debug break when it hits a break event.
5110static int message_handler_break_hit_count = 0;
5111static void DebugBreakMessageHandler(const v8::Debug::Message& message) {
5112 // Schedule a debug break for break events.
5113 if (message.IsEvent() && message.GetEvent() == v8::Break) {
5114 message_handler_break_hit_count++;
5115 if (message_handler_break_hit_count == 1) {
5116 v8::Debug::DebugBreak();
5117 }
5118 }
5119
5120 // Issue a continue command if this event will not cause the VM to start
5121 // running.
5122 if (!message.WillStartRunning()) {
5123 SendContinueCommand();
5124 }
5125}
5126
5127
5128// Test that a debug break can be scheduled while in a message handler.
5129TEST(DebugBreakInMessageHandler) {
5130 v8::HandleScope scope;
5131 DebugLocalContext env;
5132
5133 v8::Debug::SetMessageHandler2(DebugBreakMessageHandler);
5134
5135 // Test functions.
5136 const char* script = "function f() { debugger; g(); } function g() { }";
5137 CompileRun(script);
5138 v8::Local<v8::Function> f =
5139 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
5140 v8::Local<v8::Function> g =
5141 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
5142
5143 // Call f then g. The debugger statement in f will casue a break which will
5144 // cause another break.
5145 f->Call(env->Global(), 0, NULL);
5146 CHECK_EQ(2, message_handler_break_hit_count);
5147 // Calling g will not cause any additional breaks.
5148 g->Call(env->Global(), 0, NULL);
5149 CHECK_EQ(2, message_handler_break_hit_count);
5150}
5151
5152
5153#ifdef V8_NATIVE_REGEXP
5154// Debug event handler which gets the function on the top frame and schedules a
5155// break a number of times.
5156static void DebugEventDebugBreak(
5157 v8::DebugEvent event,
5158 v8::Handle<v8::Object> exec_state,
5159 v8::Handle<v8::Object> event_data,
5160 v8::Handle<v8::Value> data) {
5161
5162 if (event == v8::Break) {
5163 break_point_hit_count++;
5164
5165 // Get the name of the top frame function.
5166 if (!frame_function_name.IsEmpty()) {
5167 // Get the name of the function.
5168 const int argc = 1;
5169 v8::Handle<v8::Value> argv[argc] = { exec_state };
5170 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
5171 argc, argv);
5172 if (result->IsUndefined()) {
5173 last_function_hit[0] = '\0';
5174 } else {
5175 CHECK(result->IsString());
5176 v8::Handle<v8::String> function_name(result->ToString());
5177 function_name->WriteAscii(last_function_hit);
5178 }
5179 }
5180
5181 // Keep forcing breaks.
5182 if (break_point_hit_count < 20) {
5183 v8::Debug::DebugBreak();
5184 }
5185 }
5186}
5187
5188
5189TEST(RegExpDebugBreak) {
5190 // This test only applies to native regexps.
5191 v8::HandleScope scope;
5192 DebugLocalContext env;
5193
5194 // Create a function for checking the function when hitting a break point.
5195 frame_function_name = CompileFunction(&env,
5196 frame_function_name_source,
5197 "frame_function_name");
5198
5199 // Test RegExp which matches white spaces and comments at the begining of a
5200 // source line.
5201 const char* script =
5202 "var sourceLineBeginningSkip = /^(?:[ \\v\\h]*(?:\\/\\*.*?\\*\\/)*)*/;\n"
5203 "function f(s) { return s.match(sourceLineBeginningSkip)[0].length; }";
5204
5205 v8::Local<v8::Function> f = CompileFunction(script, "f");
5206 const int argc = 1;
5207 v8::Handle<v8::Value> argv[argc] = { v8::String::New(" /* xxx */ a=0;") };
5208 v8::Local<v8::Value> result = f->Call(env->Global(), argc, argv);
5209 CHECK_EQ(12, result->Int32Value());
5210
5211 v8::Debug::SetDebugEventListener(DebugEventDebugBreak);
5212 v8::Debug::DebugBreak();
5213 result = f->Call(env->Global(), argc, argv);
5214
5215 // Check that there was only one break event. Matching RegExp should not
5216 // cause Break events.
5217 CHECK_EQ(1, break_point_hit_count);
5218 CHECK_EQ("f", last_function_hit);
5219}
5220#endif // V8_NATIVE_REGEXP
5221
5222
5223// Common part of EvalContextData and NestedBreakEventContextData tests.
5224static void ExecuteScriptForContextCheck() {
5225 // Create a context.
5226 v8::Persistent<v8::Context> context_1;
5227 v8::Handle<v8::ObjectTemplate> global_template =
5228 v8::Handle<v8::ObjectTemplate>();
5229 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>();
5230 context_1 = v8::Context::New(NULL, global_template, global_object);
5231
5232 // Default data value is undefined.
5233 CHECK(context_1->GetData()->IsUndefined());
5234
5235 // Set and check a data value.
Steve Blockd0582a62009-12-15 09:54:21 +00005236 v8::Handle<v8::String> data_1 = v8::String::New("1");
Steve Blocka7e24c12009-10-30 11:49:00 +00005237 context_1->SetData(data_1);
5238 CHECK(context_1->GetData()->StrictEquals(data_1));
5239
5240 // Simple test function with eval that causes a break.
5241 const char* source = "function f() { eval('debugger;'); }";
5242
5243 // Enter and run function in the context.
5244 {
5245 v8::Context::Scope context_scope(context_1);
5246 expected_context = context_1;
5247 expected_context_data = data_1;
5248 v8::Local<v8::Function> f = CompileFunction(source, "f");
5249 f->Call(context_1->Global(), 0, NULL);
5250 }
5251}
5252
5253
5254// Test which creates a context and sets embedder data on it. Checks that this
5255// data is set correctly and that when the debug message handler is called for
5256// break event in an eval statement the expected context is the one returned by
5257// Message.GetEventContext.
5258TEST(EvalContextData) {
5259 v8::HandleScope scope;
5260 v8::Debug::SetMessageHandler2(ContextCheckMessageHandler);
5261
5262 ExecuteScriptForContextCheck();
5263
5264 // One time compile event and one time break event.
5265 CHECK_GT(message_handler_hit_count, 2);
5266 v8::Debug::SetMessageHandler2(NULL);
5267 CheckDebuggerUnloaded();
5268}
5269
5270
5271static bool sent_eval = false;
5272static int break_count = 0;
5273static int continue_command_send_count = 0;
5274// Check that the expected context is the one generating the debug event
5275// including the case of nested break event.
5276static void DebugEvalContextCheckMessageHandler(
5277 const v8::Debug::Message& message) {
5278 CHECK(message.GetEventContext() == expected_context);
5279 CHECK(message.GetEventContext()->GetData()->StrictEquals(
5280 expected_context_data));
5281 message_handler_hit_count++;
5282
Steve Block3ce2e202009-11-05 08:53:23 +00005283 static char print_buffer[1000];
5284 v8::String::Value json(message.GetJSON());
5285 Utf16ToAscii(*json, json.length(), print_buffer);
5286
5287 if (IsBreakEventMessage(print_buffer)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005288 break_count++;
5289 if (!sent_eval) {
5290 sent_eval = true;
5291
5292 const int kBufferSize = 1000;
5293 uint16_t buffer[kBufferSize];
5294 const char* eval_command =
5295 "{\"seq\":0,"
5296 "\"type\":\"request\","
5297 "\"command\":\"evaluate\","
5298 "arguments:{\"expression\":\"debugger;\","
5299 "\"global\":true,\"disable_break\":false}}";
5300
5301 // Send evaluate command.
5302 v8::Debug::SendCommand(buffer, AsciiToUtf16(eval_command, buffer));
5303 return;
5304 } else {
5305 // It's a break event caused by the evaluation request above.
5306 SendContinueCommand();
5307 continue_command_send_count++;
5308 }
Steve Block3ce2e202009-11-05 08:53:23 +00005309 } else if (IsEvaluateResponseMessage(print_buffer) &&
5310 continue_command_send_count < 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005311 // Response to the evaluation request. We're still on the breakpoint so
5312 // send continue.
5313 SendContinueCommand();
5314 continue_command_send_count++;
5315 }
5316}
5317
5318
5319// Tests that context returned for break event is correct when the event occurs
5320// in 'evaluate' debugger request.
5321TEST(NestedBreakEventContextData) {
5322 v8::HandleScope scope;
5323 break_count = 0;
5324 message_handler_hit_count = 0;
5325 v8::Debug::SetMessageHandler2(DebugEvalContextCheckMessageHandler);
5326
5327 ExecuteScriptForContextCheck();
5328
5329 // One time compile event and two times break event.
5330 CHECK_GT(message_handler_hit_count, 3);
5331
5332 // One break from the source and another from the evaluate request.
5333 CHECK_EQ(break_count, 2);
5334 v8::Debug::SetMessageHandler2(NULL);
5335 CheckDebuggerUnloaded();
5336}
5337
5338
5339// Debug event listener which counts the script collected events.
5340int script_collected_count = 0;
5341static void DebugEventScriptCollectedEvent(v8::DebugEvent event,
5342 v8::Handle<v8::Object> exec_state,
5343 v8::Handle<v8::Object> event_data,
5344 v8::Handle<v8::Value> data) {
5345 // Count the number of breaks.
5346 if (event == v8::ScriptCollected) {
5347 script_collected_count++;
5348 }
5349}
5350
5351
5352// Test that scripts collected are reported through the debug event listener.
5353TEST(ScriptCollectedEvent) {
5354 break_point_hit_count = 0;
5355 script_collected_count = 0;
5356 v8::HandleScope scope;
5357 DebugLocalContext env;
5358
5359 // Request the loaded scripts to initialize the debugger script cache.
5360 Debug::GetLoadedScripts();
5361
5362 // Do garbage collection to ensure that only the script in this test will be
5363 // collected afterwards.
5364 Heap::CollectAllGarbage(false);
5365
5366 script_collected_count = 0;
5367 v8::Debug::SetDebugEventListener(DebugEventScriptCollectedEvent,
5368 v8::Undefined());
5369 {
5370 v8::Script::Compile(v8::String::New("eval('a=1')"))->Run();
5371 v8::Script::Compile(v8::String::New("eval('a=2')"))->Run();
5372 }
5373
5374 // Do garbage collection to collect the script above which is no longer
5375 // referenced.
5376 Heap::CollectAllGarbage(false);
5377
5378 CHECK_EQ(2, script_collected_count);
5379
5380 v8::Debug::SetDebugEventListener(NULL);
5381 CheckDebuggerUnloaded();
5382}
5383
5384
5385// Debug event listener which counts the script collected events.
5386int script_collected_message_count = 0;
5387static void ScriptCollectedMessageHandler(const v8::Debug::Message& message) {
5388 // Count the number of scripts collected.
5389 if (message.IsEvent() && message.GetEvent() == v8::ScriptCollected) {
5390 script_collected_message_count++;
5391 v8::Handle<v8::Context> context = message.GetEventContext();
5392 CHECK(context.IsEmpty());
5393 }
5394}
5395
5396
5397// Test that GetEventContext doesn't fail and return empty handle for
5398// ScriptCollected events.
5399TEST(ScriptCollectedEventContext) {
5400 script_collected_message_count = 0;
5401 v8::HandleScope scope;
5402
5403 { // Scope for the DebugLocalContext.
5404 DebugLocalContext env;
5405
5406 // Request the loaded scripts to initialize the debugger script cache.
5407 Debug::GetLoadedScripts();
5408
5409 // Do garbage collection to ensure that only the script in this test will be
5410 // collected afterwards.
5411 Heap::CollectAllGarbage(false);
5412
5413 v8::Debug::SetMessageHandler2(ScriptCollectedMessageHandler);
5414 {
5415 v8::Script::Compile(v8::String::New("eval('a=1')"))->Run();
5416 v8::Script::Compile(v8::String::New("eval('a=2')"))->Run();
5417 }
5418 }
5419
5420 // Do garbage collection to collect the script above which is no longer
5421 // referenced.
5422 Heap::CollectAllGarbage(false);
5423
5424 CHECK_EQ(2, script_collected_message_count);
5425
5426 v8::Debug::SetMessageHandler2(NULL);
5427}
5428
5429
5430// Debug event listener which counts the after compile events.
5431int after_compile_message_count = 0;
5432static void AfterCompileMessageHandler(const v8::Debug::Message& message) {
5433 // Count the number of scripts collected.
5434 if (message.IsEvent()) {
5435 if (message.GetEvent() == v8::AfterCompile) {
5436 after_compile_message_count++;
5437 } else if (message.GetEvent() == v8::Break) {
5438 SendContinueCommand();
5439 }
5440 }
5441}
5442
5443
5444// Tests that after compile event is sent as many times as there are scripts
5445// compiled.
5446TEST(AfterCompileMessageWhenMessageHandlerIsReset) {
5447 v8::HandleScope scope;
5448 DebugLocalContext env;
5449 after_compile_message_count = 0;
5450 const char* script = "var a=1";
5451
5452 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
5453 v8::Script::Compile(v8::String::New(script))->Run();
5454 v8::Debug::SetMessageHandler2(NULL);
5455
5456 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
5457 v8::Debug::DebugBreak();
5458 v8::Script::Compile(v8::String::New(script))->Run();
5459
5460 // Setting listener to NULL should cause debugger unload.
5461 v8::Debug::SetMessageHandler2(NULL);
5462 CheckDebuggerUnloaded();
5463
5464 // Compilation cache should be disabled when debugger is active.
5465 CHECK_EQ(2, after_compile_message_count);
5466}
5467
5468
5469// Tests that break event is sent when message handler is reset.
5470TEST(BreakMessageWhenMessageHandlerIsReset) {
5471 v8::HandleScope scope;
5472 DebugLocalContext env;
5473 after_compile_message_count = 0;
5474 const char* script = "function f() {};";
5475
5476 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
5477 v8::Script::Compile(v8::String::New(script))->Run();
5478 v8::Debug::SetMessageHandler2(NULL);
5479
5480 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
5481 v8::Debug::DebugBreak();
5482 v8::Local<v8::Function> f =
5483 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
5484 f->Call(env->Global(), 0, NULL);
5485
5486 // Setting message handler to NULL should cause debugger unload.
5487 v8::Debug::SetMessageHandler2(NULL);
5488 CheckDebuggerUnloaded();
5489
5490 // Compilation cache should be disabled when debugger is active.
5491 CHECK_EQ(1, after_compile_message_count);
5492}
5493
5494
5495static int exception_event_count = 0;
5496static void ExceptionMessageHandler(const v8::Debug::Message& message) {
5497 if (message.IsEvent() && message.GetEvent() == v8::Exception) {
5498 exception_event_count++;
5499 SendContinueCommand();
5500 }
5501}
5502
5503
5504// Tests that exception event is sent when message handler is reset.
5505TEST(ExceptionMessageWhenMessageHandlerIsReset) {
5506 v8::HandleScope scope;
5507 DebugLocalContext env;
5508 exception_event_count = 0;
5509 const char* script = "function f() {throw new Error()};";
5510
5511 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
5512 v8::Script::Compile(v8::String::New(script))->Run();
5513 v8::Debug::SetMessageHandler2(NULL);
5514
5515 v8::Debug::SetMessageHandler2(ExceptionMessageHandler);
5516 v8::Local<v8::Function> f =
5517 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
5518 f->Call(env->Global(), 0, NULL);
5519
5520 // Setting message handler to NULL should cause debugger unload.
5521 v8::Debug::SetMessageHandler2(NULL);
5522 CheckDebuggerUnloaded();
5523
5524 CHECK_EQ(1, exception_event_count);
5525}
5526
5527
5528// Tests after compile event is sent when there are some provisional
5529// breakpoints out of the scripts lines range.
5530TEST(ProvisionalBreakpointOnLineOutOfRange) {
5531 v8::HandleScope scope;
5532 DebugLocalContext env;
5533 env.ExposeDebug();
5534 const char* script = "function f() {};";
5535 const char* resource_name = "test_resource";
5536
5537 // Set a couple of provisional breakpoint on lines out of the script lines
5538 // range.
5539 int sbp1 = SetScriptBreakPointByNameFromJS(resource_name, 3,
5540 -1 /* no column */);
5541 int sbp2 = SetScriptBreakPointByNameFromJS(resource_name, 5, 5);
5542
5543 after_compile_message_count = 0;
5544 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
5545
5546 v8::ScriptOrigin origin(
5547 v8::String::New(resource_name),
5548 v8::Integer::New(10),
5549 v8::Integer::New(1));
5550 // Compile a script whose first line number is greater than the breakpoints'
5551 // lines.
5552 v8::Script::Compile(v8::String::New(script), &origin)->Run();
5553
5554 // If the script is compiled successfully there is exactly one after compile
5555 // event. In case of an exception in debugger code after compile event is not
5556 // sent.
5557 CHECK_EQ(1, after_compile_message_count);
5558
5559 ClearBreakPointFromJS(sbp1);
5560 ClearBreakPointFromJS(sbp2);
5561 v8::Debug::SetMessageHandler2(NULL);
5562}
5563
5564
5565static void BreakMessageHandler(const v8::Debug::Message& message) {
5566 if (message.IsEvent() && message.GetEvent() == v8::Break) {
5567 // Count the number of breaks.
5568 break_point_hit_count++;
5569
5570 v8::HandleScope scope;
5571 v8::Handle<v8::String> json = message.GetJSON();
5572
5573 SendContinueCommand();
5574 } else if (message.IsEvent() && message.GetEvent() == v8::AfterCompile) {
5575 v8::HandleScope scope;
5576
5577 bool is_debug_break = i::StackGuard::IsDebugBreak();
5578 // Force DebugBreak flag while serializer is working.
5579 i::StackGuard::DebugBreak();
5580
5581 // Force serialization to trigger some internal JS execution.
5582 v8::Handle<v8::String> json = message.GetJSON();
5583
5584 // Restore previous state.
5585 if (is_debug_break) {
5586 i::StackGuard::DebugBreak();
5587 } else {
5588 i::StackGuard::Continue(i::DEBUGBREAK);
5589 }
5590 }
5591}
5592
5593
5594// Test that if DebugBreak is forced it is ignored when code from
5595// debug-delay.js is executed.
5596TEST(NoDebugBreakInAfterCompileMessageHandler) {
5597 v8::HandleScope scope;
5598 DebugLocalContext env;
5599
5600 // Register a debug event listener which sets the break flag and counts.
5601 v8::Debug::SetMessageHandler2(BreakMessageHandler);
5602
5603 // Set the debug break flag.
5604 v8::Debug::DebugBreak();
5605
5606 // Create a function for testing stepping.
5607 const char* src = "function f() { eval('var x = 10;'); } ";
5608 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
5609
5610 // There should be only one break event.
5611 CHECK_EQ(1, break_point_hit_count);
5612
5613 // Set the debug break flag again.
5614 v8::Debug::DebugBreak();
5615 f->Call(env->Global(), 0, NULL);
5616 // There should be one more break event when the script is evaluated in 'f'.
5617 CHECK_EQ(2, break_point_hit_count);
5618
5619 // Get rid of the debug message handler.
5620 v8::Debug::SetMessageHandler2(NULL);
5621 CheckDebuggerUnloaded();
5622}
5623
5624
5625TEST(GetMirror) {
5626 v8::HandleScope scope;
5627 DebugLocalContext env;
5628 v8::Handle<v8::Value> obj = v8::Debug::GetMirror(v8::String::New("hodja"));
5629 v8::Handle<v8::Function> run_test = v8::Handle<v8::Function>::Cast(
5630 v8::Script::New(
5631 v8::String::New(
5632 "function runTest(mirror) {"
5633 " return mirror.isString() && (mirror.length() == 5);"
5634 "}"
5635 ""
5636 "runTest;"))->Run());
5637 v8::Handle<v8::Value> result = run_test->Call(env->Global(), 1, &obj);
5638 CHECK(result->IsTrue());
5639}
Steve Blockd0582a62009-12-15 09:54:21 +00005640
5641
5642// Test that the debug break flag works with function.apply.
5643TEST(DebugBreakFunctionApply) {
5644 v8::HandleScope scope;
5645 DebugLocalContext env;
5646
5647 // Create a function for testing breaking in apply.
5648 v8::Local<v8::Function> foo = CompileFunction(
5649 &env,
5650 "function baz(x) { }"
5651 "function bar(x) { baz(); }"
5652 "function foo(){ bar.apply(this, [1]); }",
5653 "foo");
5654
5655 // Register a debug event listener which steps and counts.
5656 v8::Debug::SetDebugEventListener(DebugEventBreakMax);
5657
5658 // Set the debug break flag before calling the code using function.apply.
5659 v8::Debug::DebugBreak();
5660
5661 // Limit the number of debug breaks. This is a regression test for issue 493
5662 // where this test would enter an infinite loop.
5663 break_point_hit_count = 0;
5664 max_break_point_hit_count = 10000; // 10000 => infinite loop.
5665 foo->Call(env->Global(), 0, NULL);
5666
5667 // When keeping the debug break several break will happen.
5668 CHECK_EQ(3, break_point_hit_count);
5669
5670 v8::Debug::SetDebugEventListener(NULL);
5671 CheckDebuggerUnloaded();
5672}
5673
5674
5675v8::Handle<v8::Context> debugee_context;
5676v8::Handle<v8::Context> debugger_context;
5677
5678
5679// Property getter that checks that current and calling contexts
5680// are both the debugee contexts.
5681static v8::Handle<v8::Value> NamedGetterWithCallingContextCheck(
5682 v8::Local<v8::String> name,
5683 const v8::AccessorInfo& info) {
5684 CHECK_EQ(0, strcmp(*v8::String::AsciiValue(name), "a"));
5685 v8::Handle<v8::Context> current = v8::Context::GetCurrent();
5686 CHECK(current == debugee_context);
5687 CHECK(current != debugger_context);
5688 v8::Handle<v8::Context> calling = v8::Context::GetCalling();
5689 CHECK(calling == debugee_context);
5690 CHECK(calling != debugger_context);
5691 return v8::Int32::New(1);
5692}
5693
5694
5695// Debug event listener that checks if the first argument of a function is
5696// an object with property 'a' == 1. If the property has custom accessor
5697// this handler will eventually invoke it.
5698static void DebugEventGetAtgumentPropertyValue(
5699 v8::DebugEvent event,
5700 v8::Handle<v8::Object> exec_state,
5701 v8::Handle<v8::Object> event_data,
5702 v8::Handle<v8::Value> data) {
5703 if (event == v8::Break) {
5704 break_point_hit_count++;
5705 CHECK(debugger_context == v8::Context::GetCurrent());
5706 v8::Handle<v8::Function> func(v8::Function::Cast(*CompileRun(
5707 "(function(exec_state) {\n"
5708 " return (exec_state.frame(0).argumentValue(0).property('a').\n"
5709 " value().value() == 1);\n"
5710 "})")));
5711 const int argc = 1;
5712 v8::Handle<v8::Value> argv[argc] = { exec_state };
5713 v8::Handle<v8::Value> result = func->Call(exec_state, argc, argv);
5714 CHECK(result->IsTrue());
5715 }
5716}
5717
5718
5719TEST(CallingContextIsNotDebugContext) {
5720 // Create and enter a debugee context.
5721 v8::HandleScope scope;
5722 DebugLocalContext env;
5723 env.ExposeDebug();
5724
5725 // Save handles to the debugger and debugee contexts to be used in
5726 // NamedGetterWithCallingContextCheck.
5727 debugee_context = v8::Local<v8::Context>(*env);
5728 debugger_context = v8::Utils::ToLocal(Debug::debug_context());
5729
5730 // Create object with 'a' property accessor.
5731 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
5732 named->SetAccessor(v8::String::New("a"),
5733 NamedGetterWithCallingContextCheck);
5734 env->Global()->Set(v8::String::New("obj"),
5735 named->NewInstance());
5736
5737 // Register the debug event listener
5738 v8::Debug::SetDebugEventListener(DebugEventGetAtgumentPropertyValue);
5739
5740 // Create a function that invokes debugger.
5741 v8::Local<v8::Function> foo = CompileFunction(
5742 &env,
5743 "function bar(x) { debugger; }"
5744 "function foo(){ bar(obj); }",
5745 "foo");
5746
5747 break_point_hit_count = 0;
5748 foo->Call(env->Global(), 0, NULL);
5749 CHECK_EQ(1, break_point_hit_count);
5750
5751 v8::Debug::SetDebugEventListener(NULL);
5752 debugee_context = v8::Handle<v8::Context>();
5753 debugger_context = v8::Handle<v8::Context>();
5754 CheckDebuggerUnloaded();
5755}