blob: f5526cea9859620d71ce6623484240af3e2959da [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
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010028#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Blocka7e24c12009-10-30 11:49:00 +000029
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010030#include <stdlib.h>
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010031
Steve Blocka7e24c12009-10-30 11:49:00 +000032#include "v8.h"
33
34#include "api.h"
35#include "compilation-cache.h"
36#include "debug.h"
37#include "platform.h"
38#include "stub-cache.h"
39#include "cctest.h"
40
41
42using ::v8::internal::EmbeddedVector;
43using ::v8::internal::Object;
44using ::v8::internal::OS;
45using ::v8::internal::Handle;
46using ::v8::internal::Heap;
47using ::v8::internal::JSGlobalProxy;
48using ::v8::internal::Code;
49using ::v8::internal::Debug;
50using ::v8::internal::Debugger;
51using ::v8::internal::CommandMessage;
52using ::v8::internal::CommandMessageQueue;
53using ::v8::internal::StepAction;
54using ::v8::internal::StepIn; // From StepAction enum
55using ::v8::internal::StepNext; // From StepAction enum
56using ::v8::internal::StepOut; // From StepAction enum
57using ::v8::internal::Vector;
Steve Blockd0582a62009-12-15 09:54:21 +000058using ::v8::internal::StrLength;
Steve Blocka7e24c12009-10-30 11:49:00 +000059
60// Size of temp buffer for formatting small strings.
61#define SMALL_STRING_BUFFER_SIZE 80
62
63// --- A d d i t i o n a l C h e c k H e l p e r s
64
65
66// Helper function used by the CHECK_EQ function when given Address
67// arguments. Should not be called directly.
68static inline void CheckEqualsHelper(const char* file, int line,
69 const char* expected_source,
70 ::v8::internal::Address expected,
71 const char* value_source,
72 ::v8::internal::Address value) {
73 if (expected != value) {
74 V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n# "
75 "Expected: %i\n# Found: %i",
76 expected_source, value_source, expected, value);
77 }
78}
79
80
81// Helper function used by the CHECK_NE function when given Address
82// arguments. Should not be called directly.
83static inline void CheckNonEqualsHelper(const char* file, int line,
84 const char* unexpected_source,
85 ::v8::internal::Address unexpected,
86 const char* value_source,
87 ::v8::internal::Address value) {
88 if (unexpected == value) {
89 V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %i",
90 unexpected_source, value_source, value);
91 }
92}
93
94
95// Helper function used by the CHECK function when given code
96// arguments. Should not be called directly.
97static inline void CheckEqualsHelper(const char* file, int line,
98 const char* expected_source,
99 const Code* expected,
100 const char* value_source,
101 const Code* value) {
102 if (expected != value) {
103 V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n# "
104 "Expected: %p\n# Found: %p",
105 expected_source, value_source, expected, value);
106 }
107}
108
109
110static inline void CheckNonEqualsHelper(const char* file, int line,
111 const char* expected_source,
112 const Code* expected,
113 const char* value_source,
114 const Code* value) {
115 if (expected == value) {
116 V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %p",
117 expected_source, value_source, value);
118 }
119}
120
121
122// --- H e l p e r C l a s s e s
123
124
125// Helper class for creating a V8 enviromnent for running tests
126class DebugLocalContext {
127 public:
128 inline DebugLocalContext(
129 v8::ExtensionConfiguration* extensions = 0,
130 v8::Handle<v8::ObjectTemplate> global_template =
131 v8::Handle<v8::ObjectTemplate>(),
132 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>())
133 : context_(v8::Context::New(extensions, global_template, global_object)) {
134 context_->Enter();
135 }
136 inline ~DebugLocalContext() {
137 context_->Exit();
138 context_.Dispose();
139 }
140 inline v8::Context* operator->() { return *context_; }
141 inline v8::Context* operator*() { return *context_; }
142 inline bool IsReady() { return !context_.IsEmpty(); }
143 void ExposeDebug() {
144 // Expose the debug context global object in the global object for testing.
145 Debug::Load();
146 Debug::debug_context()->set_security_token(
147 v8::Utils::OpenHandle(*context_)->security_token());
148
149 Handle<JSGlobalProxy> global(Handle<JSGlobalProxy>::cast(
150 v8::Utils::OpenHandle(*context_->Global())));
151 Handle<v8::internal::String> debug_string =
152 v8::internal::Factory::LookupAsciiSymbol("debug");
153 SetProperty(global, debug_string,
154 Handle<Object>(Debug::debug_context()->global_proxy()), DONT_ENUM);
155 }
156 private:
157 v8::Persistent<v8::Context> context_;
158};
159
160
161// --- H e l p e r F u n c t i o n s
162
163
164// Compile and run the supplied source and return the fequested function.
165static v8::Local<v8::Function> CompileFunction(DebugLocalContext* env,
166 const char* source,
167 const char* function_name) {
168 v8::Script::Compile(v8::String::New(source))->Run();
169 return v8::Local<v8::Function>::Cast(
170 (*env)->Global()->Get(v8::String::New(function_name)));
171}
172
173
174// Compile and run the supplied source and return the requested function.
175static v8::Local<v8::Function> CompileFunction(const char* source,
176 const char* function_name) {
177 v8::Script::Compile(v8::String::New(source))->Run();
178 return v8::Local<v8::Function>::Cast(
179 v8::Context::GetCurrent()->Global()->Get(v8::String::New(function_name)));
180}
181
182
Steve Blocka7e24c12009-10-30 11:49:00 +0000183// Is there any debug info for the function?
184static bool HasDebugInfo(v8::Handle<v8::Function> fun) {
185 Handle<v8::internal::JSFunction> f = v8::Utils::OpenHandle(*fun);
186 Handle<v8::internal::SharedFunctionInfo> shared(f->shared());
187 return Debug::HasDebugInfo(shared);
188}
189
190
191// Set a break point in a function and return the associated break point
192// number.
193static int SetBreakPoint(Handle<v8::internal::JSFunction> fun, int position) {
194 static int break_point = 0;
195 Handle<v8::internal::SharedFunctionInfo> shared(fun->shared());
196 Debug::SetBreakPoint(
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100197 shared,
198 Handle<Object>(v8::internal::Smi::FromInt(++break_point)),
199 &position);
Steve Blocka7e24c12009-10-30 11:49:00 +0000200 return break_point;
201}
202
203
204// Set a break point in a function and return the associated break point
205// number.
206static int SetBreakPoint(v8::Handle<v8::Function> fun, int position) {
207 return SetBreakPoint(v8::Utils::OpenHandle(*fun), position);
208}
209
210
211// Set a break point in a function using the Debug object and return the
212// associated break point number.
213static int SetBreakPointFromJS(const char* function_name,
214 int line, int position) {
215 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
216 OS::SNPrintF(buffer,
217 "debug.Debug.setBreakPoint(%s,%d,%d)",
218 function_name, line, position);
219 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
220 v8::Handle<v8::String> str = v8::String::New(buffer.start());
221 return v8::Script::Compile(str)->Run()->Int32Value();
222}
223
224
225// Set a break point in a script identified by id using the global Debug object.
226static int SetScriptBreakPointByIdFromJS(int script_id, int line, int column) {
227 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
228 if (column >= 0) {
229 // Column specified set script break point on precise location.
230 OS::SNPrintF(buffer,
231 "debug.Debug.setScriptBreakPointById(%d,%d,%d)",
232 script_id, line, column);
233 } else {
234 // Column not specified set script break point on line.
235 OS::SNPrintF(buffer,
236 "debug.Debug.setScriptBreakPointById(%d,%d)",
237 script_id, line);
238 }
239 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
240 {
241 v8::TryCatch try_catch;
242 v8::Handle<v8::String> str = v8::String::New(buffer.start());
243 v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run();
244 CHECK(!try_catch.HasCaught());
245 return value->Int32Value();
246 }
247}
248
249
250// Set a break point in a script identified by name using the global Debug
251// object.
252static int SetScriptBreakPointByNameFromJS(const char* script_name,
253 int line, int column) {
254 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
255 if (column >= 0) {
256 // Column specified set script break point on precise location.
257 OS::SNPrintF(buffer,
258 "debug.Debug.setScriptBreakPointByName(\"%s\",%d,%d)",
259 script_name, line, column);
260 } else {
261 // Column not specified set script break point on line.
262 OS::SNPrintF(buffer,
263 "debug.Debug.setScriptBreakPointByName(\"%s\",%d)",
264 script_name, line);
265 }
266 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
267 {
268 v8::TryCatch try_catch;
269 v8::Handle<v8::String> str = v8::String::New(buffer.start());
270 v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run();
271 CHECK(!try_catch.HasCaught());
272 return value->Int32Value();
273 }
274}
275
276
277// Clear a break point.
278static void ClearBreakPoint(int break_point) {
279 Debug::ClearBreakPoint(
280 Handle<Object>(v8::internal::Smi::FromInt(break_point)));
281}
282
283
284// Clear a break point using the global Debug object.
285static void ClearBreakPointFromJS(int break_point_number) {
286 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
287 OS::SNPrintF(buffer,
288 "debug.Debug.clearBreakPoint(%d)",
289 break_point_number);
290 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
291 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
292}
293
294
295static void EnableScriptBreakPointFromJS(int break_point_number) {
296 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
297 OS::SNPrintF(buffer,
298 "debug.Debug.enableScriptBreakPoint(%d)",
299 break_point_number);
300 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
301 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
302}
303
304
305static void DisableScriptBreakPointFromJS(int break_point_number) {
306 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
307 OS::SNPrintF(buffer,
308 "debug.Debug.disableScriptBreakPoint(%d)",
309 break_point_number);
310 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
311 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
312}
313
314
315static void ChangeScriptBreakPointConditionFromJS(int break_point_number,
316 const char* condition) {
317 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
318 OS::SNPrintF(buffer,
319 "debug.Debug.changeScriptBreakPointCondition(%d, \"%s\")",
320 break_point_number, condition);
321 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
322 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
323}
324
325
326static void ChangeScriptBreakPointIgnoreCountFromJS(int break_point_number,
327 int ignoreCount) {
328 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
329 OS::SNPrintF(buffer,
330 "debug.Debug.changeScriptBreakPointIgnoreCount(%d, %d)",
331 break_point_number, ignoreCount);
332 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
333 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
334}
335
336
337// Change break on exception.
338static void ChangeBreakOnException(bool caught, bool uncaught) {
339 Debug::ChangeBreakOnException(v8::internal::BreakException, caught);
340 Debug::ChangeBreakOnException(v8::internal::BreakUncaughtException, uncaught);
341}
342
343
344// Change break on exception using the global Debug object.
345static void ChangeBreakOnExceptionFromJS(bool caught, bool uncaught) {
346 if (caught) {
347 v8::Script::Compile(
348 v8::String::New("debug.Debug.setBreakOnException()"))->Run();
349 } else {
350 v8::Script::Compile(
351 v8::String::New("debug.Debug.clearBreakOnException()"))->Run();
352 }
353 if (uncaught) {
354 v8::Script::Compile(
355 v8::String::New("debug.Debug.setBreakOnUncaughtException()"))->Run();
356 } else {
357 v8::Script::Compile(
358 v8::String::New("debug.Debug.clearBreakOnUncaughtException()"))->Run();
359 }
360}
361
362
363// Prepare to step to next break location.
364static void PrepareStep(StepAction step_action) {
365 Debug::PrepareStep(step_action, 1);
366}
367
368
369// This function is in namespace v8::internal to be friend with class
370// v8::internal::Debug.
371namespace v8 {
372namespace internal {
373
374// Collect the currently debugged functions.
375Handle<FixedArray> GetDebuggedFunctions() {
376 v8::internal::DebugInfoListNode* node = Debug::debug_info_list_;
377
378 // Find the number of debugged functions.
379 int count = 0;
380 while (node) {
381 count++;
382 node = node->next();
383 }
384
385 // Allocate array for the debugged functions
386 Handle<FixedArray> debugged_functions =
387 v8::internal::Factory::NewFixedArray(count);
388
389 // Run through the debug info objects and collect all functions.
390 count = 0;
391 while (node) {
392 debugged_functions->set(count++, *node->debug_info());
393 node = node->next();
394 }
395
396 return debugged_functions;
397}
398
399
400static Handle<Code> ComputeCallDebugBreak(int argc) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100401 CALL_HEAP_FUNCTION(
402 v8::internal::StubCache::ComputeCallDebugBreak(argc, Code::CALL_IC),
403 Code);
Steve Blocka7e24c12009-10-30 11:49:00 +0000404}
405
406
407// Check that the debugger has been fully unloaded.
408void CheckDebuggerUnloaded(bool check_functions) {
409 // Check that the debugger context is cleared and that there is no debug
410 // information stored for the debugger.
411 CHECK(Debug::debug_context().is_null());
412 CHECK_EQ(NULL, Debug::debug_info_list_);
413
414 // Collect garbage to ensure weak handles are cleared.
415 Heap::CollectAllGarbage(false);
416 Heap::CollectAllGarbage(false);
417
418 // Iterate the head and check that there are no debugger related objects left.
419 HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +0000420 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000421 CHECK(!obj->IsDebugInfo());
422 CHECK(!obj->IsBreakPointInfo());
423
424 // If deep check of functions is requested check that no debug break code
425 // is left in all functions.
426 if (check_functions) {
427 if (obj->IsJSFunction()) {
428 JSFunction* fun = JSFunction::cast(obj);
429 for (RelocIterator it(fun->shared()->code()); !it.done(); it.next()) {
430 RelocInfo::Mode rmode = it.rinfo()->rmode();
431 if (RelocInfo::IsCodeTarget(rmode)) {
432 CHECK(!Debug::IsDebugBreak(it.rinfo()->target_address()));
433 } else if (RelocInfo::IsJSReturn(rmode)) {
434 CHECK(!Debug::IsDebugBreakAtReturn(it.rinfo()));
435 }
436 }
437 }
438 }
439 }
440}
441
442
Steve Block6ded16b2010-05-10 14:33:55 +0100443void ForceUnloadDebugger() {
444 Debugger::never_unload_debugger_ = false;
445 Debugger::UnloadDebugger();
446}
447
448
Steve Blocka7e24c12009-10-30 11:49:00 +0000449} } // namespace v8::internal
450
451
452// Check that the debugger has been fully unloaded.
453static void CheckDebuggerUnloaded(bool check_functions = false) {
Leon Clarkee46be812010-01-19 14:06:41 +0000454 // Let debugger to unload itself synchronously
455 v8::Debug::ProcessDebugMessages();
456
Steve Blocka7e24c12009-10-30 11:49:00 +0000457 v8::internal::CheckDebuggerUnloaded(check_functions);
458}
459
460
461// Inherit from BreakLocationIterator to get access to protected parts for
462// testing.
463class TestBreakLocationIterator: public v8::internal::BreakLocationIterator {
464 public:
465 explicit TestBreakLocationIterator(Handle<v8::internal::DebugInfo> debug_info)
466 : BreakLocationIterator(debug_info, v8::internal::SOURCE_BREAK_LOCATIONS) {}
467 v8::internal::RelocIterator* it() { return reloc_iterator_; }
468 v8::internal::RelocIterator* it_original() {
469 return reloc_iterator_original_;
470 }
471};
472
473
474// Compile a function, set a break point and check that the call at the break
475// location in the code is the expected debug_break function.
476void CheckDebugBreakFunction(DebugLocalContext* env,
477 const char* source, const char* name,
478 int position, v8::internal::RelocInfo::Mode mode,
479 Code* debug_break) {
480 // Create function and set the break point.
481 Handle<v8::internal::JSFunction> fun = v8::Utils::OpenHandle(
482 *CompileFunction(env, source, name));
483 int bp = SetBreakPoint(fun, position);
484
485 // Check that the debug break function is as expected.
486 Handle<v8::internal::SharedFunctionInfo> shared(fun->shared());
487 CHECK(Debug::HasDebugInfo(shared));
488 TestBreakLocationIterator it1(Debug::GetDebugInfo(shared));
489 it1.FindBreakLocationFromPosition(position);
490 CHECK_EQ(mode, it1.it()->rinfo()->rmode());
491 if (mode != v8::internal::RelocInfo::JS_RETURN) {
492 CHECK_EQ(debug_break,
493 Code::GetCodeFromTargetAddress(it1.it()->rinfo()->target_address()));
494 } else {
495 CHECK(Debug::IsDebugBreakAtReturn(it1.it()->rinfo()));
496 }
497
498 // Clear the break point and check that the debug break function is no longer
499 // there
500 ClearBreakPoint(bp);
501 CHECK(!Debug::HasDebugInfo(shared));
502 CHECK(Debug::EnsureDebugInfo(shared));
503 TestBreakLocationIterator it2(Debug::GetDebugInfo(shared));
504 it2.FindBreakLocationFromPosition(position);
505 CHECK_EQ(mode, it2.it()->rinfo()->rmode());
506 if (mode == v8::internal::RelocInfo::JS_RETURN) {
507 CHECK(!Debug::IsDebugBreakAtReturn(it2.it()->rinfo()));
508 }
509}
510
511
512// --- D e b u g E v e n t H a n d l e r s
513// ---
514// --- The different tests uses a number of debug event handlers.
515// ---
516
517
518// Source for The JavaScript function which picks out the function name of the
519// top frame.
520const char* frame_function_name_source =
521 "function frame_function_name(exec_state) {"
522 " return exec_state.frame(0).func().name();"
523 "}";
524v8::Local<v8::Function> frame_function_name;
525
526
527// Source for The JavaScript function which picks out the source line for the
528// top frame.
529const char* frame_source_line_source =
530 "function frame_source_line(exec_state) {"
531 " return exec_state.frame(0).sourceLine();"
532 "}";
533v8::Local<v8::Function> frame_source_line;
534
535
536// Source for The JavaScript function which picks out the source column for the
537// top frame.
538const char* frame_source_column_source =
539 "function frame_source_column(exec_state) {"
540 " return exec_state.frame(0).sourceColumn();"
541 "}";
542v8::Local<v8::Function> frame_source_column;
543
544
545// Source for The JavaScript function which picks out the script name for the
546// top frame.
547const char* frame_script_name_source =
548 "function frame_script_name(exec_state) {"
549 " return exec_state.frame(0).func().script().name();"
550 "}";
551v8::Local<v8::Function> frame_script_name;
552
553
554// Source for The JavaScript function which picks out the script data for the
555// top frame.
556const char* frame_script_data_source =
557 "function frame_script_data(exec_state) {"
558 " return exec_state.frame(0).func().script().data();"
559 "}";
560v8::Local<v8::Function> frame_script_data;
561
562
Andrei Popescu402d9372010-02-26 13:31:12 +0000563// Source for The JavaScript function which picks out the script data from
564// AfterCompile event
565const char* compiled_script_data_source =
566 "function compiled_script_data(event_data) {"
567 " return event_data.script().data();"
568 "}";
569v8::Local<v8::Function> compiled_script_data;
570
571
Steve Blocka7e24c12009-10-30 11:49:00 +0000572// Source for The JavaScript function which returns the number of frames.
573static const char* frame_count_source =
574 "function frame_count(exec_state) {"
575 " return exec_state.frameCount();"
576 "}";
577v8::Handle<v8::Function> frame_count;
578
579
580// Global variable to store the last function hit - used by some tests.
581char last_function_hit[80];
582
583// Global variable to store the name and data for last script hit - used by some
584// tests.
585char last_script_name_hit[80];
586char last_script_data_hit[80];
587
588// Global variables to store the last source position - used by some tests.
589int last_source_line = -1;
590int last_source_column = -1;
591
592// Debug event handler which counts the break points which have been hit.
593int break_point_hit_count = 0;
594static void DebugEventBreakPointHitCount(v8::DebugEvent event,
595 v8::Handle<v8::Object> exec_state,
596 v8::Handle<v8::Object> event_data,
597 v8::Handle<v8::Value> data) {
598 // When hitting a debug event listener there must be a break set.
599 CHECK_NE(v8::internal::Debug::break_id(), 0);
600
601 // Count the number of breaks.
602 if (event == v8::Break) {
603 break_point_hit_count++;
604 if (!frame_function_name.IsEmpty()) {
605 // Get the name of the function.
606 const int argc = 1;
607 v8::Handle<v8::Value> argv[argc] = { exec_state };
608 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
609 argc, argv);
610 if (result->IsUndefined()) {
611 last_function_hit[0] = '\0';
612 } else {
613 CHECK(result->IsString());
614 v8::Handle<v8::String> function_name(result->ToString());
615 function_name->WriteAscii(last_function_hit);
616 }
617 }
618
619 if (!frame_source_line.IsEmpty()) {
620 // Get the source line.
621 const int argc = 1;
622 v8::Handle<v8::Value> argv[argc] = { exec_state };
623 v8::Handle<v8::Value> result = frame_source_line->Call(exec_state,
624 argc, argv);
625 CHECK(result->IsNumber());
626 last_source_line = result->Int32Value();
627 }
628
629 if (!frame_source_column.IsEmpty()) {
630 // Get the source column.
631 const int argc = 1;
632 v8::Handle<v8::Value> argv[argc] = { exec_state };
633 v8::Handle<v8::Value> result = frame_source_column->Call(exec_state,
634 argc, argv);
635 CHECK(result->IsNumber());
636 last_source_column = result->Int32Value();
637 }
638
639 if (!frame_script_name.IsEmpty()) {
640 // Get the script name of the function script.
641 const int argc = 1;
642 v8::Handle<v8::Value> argv[argc] = { exec_state };
643 v8::Handle<v8::Value> result = frame_script_name->Call(exec_state,
644 argc, argv);
645 if (result->IsUndefined()) {
646 last_script_name_hit[0] = '\0';
647 } else {
648 CHECK(result->IsString());
649 v8::Handle<v8::String> script_name(result->ToString());
650 script_name->WriteAscii(last_script_name_hit);
651 }
652 }
653
654 if (!frame_script_data.IsEmpty()) {
655 // Get the script data of the function script.
656 const int argc = 1;
657 v8::Handle<v8::Value> argv[argc] = { exec_state };
658 v8::Handle<v8::Value> result = frame_script_data->Call(exec_state,
659 argc, argv);
660 if (result->IsUndefined()) {
661 last_script_data_hit[0] = '\0';
662 } else {
663 result = result->ToString();
664 CHECK(result->IsString());
665 v8::Handle<v8::String> script_data(result->ToString());
666 script_data->WriteAscii(last_script_data_hit);
667 }
668 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000669 } else if (event == v8::AfterCompile && !compiled_script_data.IsEmpty()) {
670 const int argc = 1;
671 v8::Handle<v8::Value> argv[argc] = { event_data };
672 v8::Handle<v8::Value> result = compiled_script_data->Call(exec_state,
673 argc, argv);
674 if (result->IsUndefined()) {
675 last_script_data_hit[0] = '\0';
676 } else {
677 result = result->ToString();
678 CHECK(result->IsString());
679 v8::Handle<v8::String> script_data(result->ToString());
680 script_data->WriteAscii(last_script_data_hit);
681 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000682 }
683}
684
685
686// Debug event handler which counts a number of events and collects the stack
687// height if there is a function compiled for that.
688int exception_hit_count = 0;
689int uncaught_exception_hit_count = 0;
690int last_js_stack_height = -1;
691
692static void DebugEventCounterClear() {
693 break_point_hit_count = 0;
694 exception_hit_count = 0;
695 uncaught_exception_hit_count = 0;
696}
697
698static void DebugEventCounter(v8::DebugEvent event,
699 v8::Handle<v8::Object> exec_state,
700 v8::Handle<v8::Object> event_data,
701 v8::Handle<v8::Value> data) {
702 // When hitting a debug event listener there must be a break set.
703 CHECK_NE(v8::internal::Debug::break_id(), 0);
704
705 // Count the number of breaks.
706 if (event == v8::Break) {
707 break_point_hit_count++;
708 } else if (event == v8::Exception) {
709 exception_hit_count++;
710
711 // Check whether the exception was uncaught.
712 v8::Local<v8::String> fun_name = v8::String::New("uncaught");
713 v8::Local<v8::Function> fun =
714 v8::Function::Cast(*event_data->Get(fun_name));
715 v8::Local<v8::Value> result = *fun->Call(event_data, 0, NULL);
716 if (result->IsTrue()) {
717 uncaught_exception_hit_count++;
718 }
719 }
720
721 // Collect the JavsScript stack height if the function frame_count is
722 // compiled.
723 if (!frame_count.IsEmpty()) {
724 static const int kArgc = 1;
725 v8::Handle<v8::Value> argv[kArgc] = { exec_state };
726 // Using exec_state as receiver is just to have a receiver.
727 v8::Handle<v8::Value> result = frame_count->Call(exec_state, kArgc, argv);
728 last_js_stack_height = result->Int32Value();
729 }
730}
731
732
733// Debug event handler which evaluates a number of expressions when a break
734// point is hit. Each evaluated expression is compared with an expected value.
735// For this debug event handler to work the following two global varaibles
736// must be initialized.
737// checks: An array of expressions and expected results
738// evaluate_check_function: A JavaScript function (see below)
739
740// Structure for holding checks to do.
741struct EvaluateCheck {
742 const char* expr; // An expression to evaluate when a break point is hit.
743 v8::Handle<v8::Value> expected; // The expected result.
744};
745// Array of checks to do.
746struct EvaluateCheck* checks = NULL;
747// Source for The JavaScript function which can do the evaluation when a break
748// point is hit.
749const char* evaluate_check_source =
750 "function evaluate_check(exec_state, expr, expected) {"
751 " return exec_state.frame(0).evaluate(expr).value() === expected;"
752 "}";
753v8::Local<v8::Function> evaluate_check_function;
754
755// The actual debug event described by the longer comment above.
756static void DebugEventEvaluate(v8::DebugEvent event,
757 v8::Handle<v8::Object> exec_state,
758 v8::Handle<v8::Object> event_data,
759 v8::Handle<v8::Value> data) {
760 // When hitting a debug event listener there must be a break set.
761 CHECK_NE(v8::internal::Debug::break_id(), 0);
762
763 if (event == v8::Break) {
764 for (int i = 0; checks[i].expr != NULL; i++) {
765 const int argc = 3;
766 v8::Handle<v8::Value> argv[argc] = { exec_state,
767 v8::String::New(checks[i].expr),
768 checks[i].expected };
769 v8::Handle<v8::Value> result =
770 evaluate_check_function->Call(exec_state, argc, argv);
771 if (!result->IsTrue()) {
772 v8::String::AsciiValue ascii(checks[i].expected->ToString());
773 V8_Fatal(__FILE__, __LINE__, "%s != %s", checks[i].expr, *ascii);
774 }
775 }
776 }
777}
778
779
780// This debug event listener removes a breakpoint in a function
781int debug_event_remove_break_point = 0;
782static void DebugEventRemoveBreakPoint(v8::DebugEvent event,
783 v8::Handle<v8::Object> exec_state,
784 v8::Handle<v8::Object> event_data,
785 v8::Handle<v8::Value> data) {
786 // When hitting a debug event listener there must be a break set.
787 CHECK_NE(v8::internal::Debug::break_id(), 0);
788
789 if (event == v8::Break) {
790 break_point_hit_count++;
791 v8::Handle<v8::Function> fun = v8::Handle<v8::Function>::Cast(data);
792 ClearBreakPoint(debug_event_remove_break_point);
793 }
794}
795
796
797// Debug event handler which counts break points hit and performs a step
798// afterwards.
799StepAction step_action = StepIn; // Step action to perform when stepping.
800static void DebugEventStep(v8::DebugEvent event,
801 v8::Handle<v8::Object> exec_state,
802 v8::Handle<v8::Object> event_data,
803 v8::Handle<v8::Value> data) {
804 // When hitting a debug event listener there must be a break set.
805 CHECK_NE(v8::internal::Debug::break_id(), 0);
806
807 if (event == v8::Break) {
808 break_point_hit_count++;
809 PrepareStep(step_action);
810 }
811}
812
813
814// Debug event handler which counts break points hit and performs a step
815// afterwards. For each call the expected function is checked.
816// For this debug event handler to work the following two global varaibles
817// must be initialized.
818// expected_step_sequence: An array of the expected function call sequence.
819// frame_function_name: A JavaScript function (see below).
820
821// String containing the expected function call sequence. Note: this only works
822// if functions have name length of one.
823const char* expected_step_sequence = NULL;
824
825// The actual debug event described by the longer comment above.
826static void DebugEventStepSequence(v8::DebugEvent event,
827 v8::Handle<v8::Object> exec_state,
828 v8::Handle<v8::Object> event_data,
829 v8::Handle<v8::Value> data) {
830 // When hitting a debug event listener there must be a break set.
831 CHECK_NE(v8::internal::Debug::break_id(), 0);
832
833 if (event == v8::Break || event == v8::Exception) {
834 // Check that the current function is the expected.
835 CHECK(break_point_hit_count <
Steve Blockd0582a62009-12-15 09:54:21 +0000836 StrLength(expected_step_sequence));
Steve Blocka7e24c12009-10-30 11:49:00 +0000837 const int argc = 1;
838 v8::Handle<v8::Value> argv[argc] = { exec_state };
839 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
840 argc, argv);
841 CHECK(result->IsString());
842 v8::String::AsciiValue function_name(result->ToString());
Steve Blockd0582a62009-12-15 09:54:21 +0000843 CHECK_EQ(1, StrLength(*function_name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000844 CHECK_EQ((*function_name)[0],
845 expected_step_sequence[break_point_hit_count]);
846
847 // Perform step.
848 break_point_hit_count++;
849 PrepareStep(step_action);
850 }
851}
852
853
854// Debug event handler which performs a garbage collection.
855static void DebugEventBreakPointCollectGarbage(
856 v8::DebugEvent event,
857 v8::Handle<v8::Object> exec_state,
858 v8::Handle<v8::Object> event_data,
859 v8::Handle<v8::Value> data) {
860 // When hitting a debug event listener there must be a break set.
861 CHECK_NE(v8::internal::Debug::break_id(), 0);
862
863 // Perform a garbage collection when break point is hit and continue. Based
864 // on the number of break points hit either scavenge or mark compact
865 // collector is used.
866 if (event == v8::Break) {
867 break_point_hit_count++;
868 if (break_point_hit_count % 2 == 0) {
869 // Scavenge.
870 Heap::CollectGarbage(0, v8::internal::NEW_SPACE);
871 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100872 // Mark sweep compact.
873 Heap::CollectAllGarbage(true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000874 }
875 }
876}
877
878
879// Debug event handler which re-issues a debug break and calls the garbage
880// collector to have the heap verified.
881static void DebugEventBreak(v8::DebugEvent event,
882 v8::Handle<v8::Object> exec_state,
883 v8::Handle<v8::Object> event_data,
884 v8::Handle<v8::Value> data) {
885 // When hitting a debug event listener there must be a break set.
886 CHECK_NE(v8::internal::Debug::break_id(), 0);
887
888 if (event == v8::Break) {
889 // Count the number of breaks.
890 break_point_hit_count++;
891
892 // Run the garbage collector to enforce heap verification if option
893 // --verify-heap is set.
894 Heap::CollectGarbage(0, v8::internal::NEW_SPACE);
895
896 // Set the break flag again to come back here as soon as possible.
897 v8::Debug::DebugBreak();
898 }
899}
900
901
Steve Blockd0582a62009-12-15 09:54:21 +0000902// Debug event handler which re-issues a debug break until a limit has been
903// reached.
904int max_break_point_hit_count = 0;
905static void DebugEventBreakMax(v8::DebugEvent event,
906 v8::Handle<v8::Object> exec_state,
907 v8::Handle<v8::Object> event_data,
908 v8::Handle<v8::Value> data) {
909 // When hitting a debug event listener there must be a break set.
910 CHECK_NE(v8::internal::Debug::break_id(), 0);
911
912 if (event == v8::Break && break_point_hit_count < max_break_point_hit_count) {
913 // Count the number of breaks.
914 break_point_hit_count++;
915
916 // Set the break flag again to come back here as soon as possible.
917 v8::Debug::DebugBreak();
918 }
919}
920
921
Steve Blocka7e24c12009-10-30 11:49:00 +0000922// --- M e s s a g e C a l l b a c k
923
924
925// Message callback which counts the number of messages.
926int message_callback_count = 0;
927
928static void MessageCallbackCountClear() {
929 message_callback_count = 0;
930}
931
932static void MessageCallbackCount(v8::Handle<v8::Message> message,
933 v8::Handle<v8::Value> data) {
934 message_callback_count++;
935}
936
937
938// --- T h e A c t u a l T e s t s
939
940
941// Test that the debug break function is the expected one for different kinds
942// of break locations.
943TEST(DebugStub) {
944 using ::v8::internal::Builtins;
945 v8::HandleScope scope;
946 DebugLocalContext env;
947
948 CheckDebugBreakFunction(&env,
949 "function f1(){}", "f1",
950 0,
951 v8::internal::RelocInfo::JS_RETURN,
952 NULL);
953 CheckDebugBreakFunction(&env,
954 "function f2(){x=1;}", "f2",
955 0,
956 v8::internal::RelocInfo::CODE_TARGET,
957 Builtins::builtin(Builtins::StoreIC_DebugBreak));
958 CheckDebugBreakFunction(&env,
959 "function f3(){var a=x;}", "f3",
960 0,
961 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
962 Builtins::builtin(Builtins::LoadIC_DebugBreak));
963
964// TODO(1240753): Make the test architecture independent or split
965// parts of the debugger into architecture dependent files. This
966// part currently disabled as it is not portable between IA32/ARM.
967// Currently on ICs for keyed store/load on ARM.
968#if !defined (__arm__) && !defined(__thumb__)
969 CheckDebugBreakFunction(
970 &env,
971 "function f4(){var index='propertyName'; var a={}; a[index] = 'x';}",
972 "f4",
973 0,
974 v8::internal::RelocInfo::CODE_TARGET,
975 Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak));
976 CheckDebugBreakFunction(
977 &env,
978 "function f5(){var index='propertyName'; var a={}; return a[index];}",
979 "f5",
980 0,
981 v8::internal::RelocInfo::CODE_TARGET,
982 Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak));
983#endif
984
985 // Check the debug break code stubs for call ICs with different number of
986 // parameters.
987 Handle<Code> debug_break_0 = v8::internal::ComputeCallDebugBreak(0);
988 Handle<Code> debug_break_1 = v8::internal::ComputeCallDebugBreak(1);
989 Handle<Code> debug_break_4 = v8::internal::ComputeCallDebugBreak(4);
990
991 CheckDebugBreakFunction(&env,
992 "function f4_0(){x();}", "f4_0",
993 0,
994 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
995 *debug_break_0);
996
997 CheckDebugBreakFunction(&env,
998 "function f4_1(){x(1);}", "f4_1",
999 0,
1000 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
1001 *debug_break_1);
1002
1003 CheckDebugBreakFunction(&env,
1004 "function f4_4(){x(1,2,3,4);}", "f4_4",
1005 0,
1006 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
1007 *debug_break_4);
1008}
1009
1010
1011// Test that the debug info in the VM is in sync with the functions being
1012// debugged.
1013TEST(DebugInfo) {
1014 v8::HandleScope scope;
1015 DebugLocalContext env;
1016 // Create a couple of functions for the test.
1017 v8::Local<v8::Function> foo =
1018 CompileFunction(&env, "function foo(){}", "foo");
1019 v8::Local<v8::Function> bar =
1020 CompileFunction(&env, "function bar(){}", "bar");
1021 // Initially no functions are debugged.
1022 CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
1023 CHECK(!HasDebugInfo(foo));
1024 CHECK(!HasDebugInfo(bar));
1025 // One function (foo) is debugged.
1026 int bp1 = SetBreakPoint(foo, 0);
1027 CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
1028 CHECK(HasDebugInfo(foo));
1029 CHECK(!HasDebugInfo(bar));
1030 // Two functions are debugged.
1031 int bp2 = SetBreakPoint(bar, 0);
1032 CHECK_EQ(2, v8::internal::GetDebuggedFunctions()->length());
1033 CHECK(HasDebugInfo(foo));
1034 CHECK(HasDebugInfo(bar));
1035 // One function (bar) is debugged.
1036 ClearBreakPoint(bp1);
1037 CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
1038 CHECK(!HasDebugInfo(foo));
1039 CHECK(HasDebugInfo(bar));
1040 // No functions are debugged.
1041 ClearBreakPoint(bp2);
1042 CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
1043 CHECK(!HasDebugInfo(foo));
1044 CHECK(!HasDebugInfo(bar));
1045}
1046
1047
1048// Test that a break point can be set at an IC store location.
1049TEST(BreakPointICStore) {
1050 break_point_hit_count = 0;
1051 v8::HandleScope scope;
1052 DebugLocalContext env;
1053
1054 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1055 v8::Undefined());
1056 v8::Script::Compile(v8::String::New("function foo(){bar=0;}"))->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 load location.
1082TEST(BreakPointICLoad) {
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("bar=1"))->Run();
1089 v8::Script::Compile(v8::String::New("function foo(){var x=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 an IC call location.
1115TEST(BreakPointICCall) {
1116 break_point_hit_count = 0;
1117 v8::HandleScope scope;
1118 DebugLocalContext env;
1119 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1120 v8::Undefined());
1121 v8::Script::Compile(v8::String::New("function bar(){}"))->Run();
1122 v8::Script::Compile(v8::String::New("function foo(){bar();}"))->Run();
1123 v8::Local<v8::Function> foo =
1124 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1125
1126 // Run without breakpoints.
1127 foo->Call(env->Global(), 0, NULL);
1128 CHECK_EQ(0, break_point_hit_count);
1129
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001130 // Run with breakpoint.
Steve Blocka7e24c12009-10-30 11:49:00 +00001131 int bp = SetBreakPoint(foo, 0);
1132 foo->Call(env->Global(), 0, NULL);
1133 CHECK_EQ(1, break_point_hit_count);
1134 foo->Call(env->Global(), 0, NULL);
1135 CHECK_EQ(2, break_point_hit_count);
1136
1137 // Run without breakpoints.
1138 ClearBreakPoint(bp);
1139 foo->Call(env->Global(), 0, NULL);
1140 CHECK_EQ(2, break_point_hit_count);
1141
1142 v8::Debug::SetDebugEventListener(NULL);
1143 CheckDebuggerUnloaded();
1144}
1145
1146
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001147// Test that a break point can be set at an IC call location and survive a GC.
1148TEST(BreakPointICCallWithGC) {
1149 break_point_hit_count = 0;
1150 v8::HandleScope scope;
1151 DebugLocalContext env;
1152 v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage,
1153 v8::Undefined());
1154 v8::Script::Compile(v8::String::New("function bar(){return 1;}"))->Run();
1155 v8::Script::Compile(v8::String::New("function foo(){return bar();}"))->Run();
1156 v8::Local<v8::Function> foo =
1157 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1158
1159 // Run without breakpoints.
1160 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1161 CHECK_EQ(0, break_point_hit_count);
1162
1163 // Run with breakpoint.
1164 int bp = SetBreakPoint(foo, 0);
1165 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1166 CHECK_EQ(1, break_point_hit_count);
1167 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1168 CHECK_EQ(2, break_point_hit_count);
1169
1170 // Run without breakpoints.
1171 ClearBreakPoint(bp);
1172 foo->Call(env->Global(), 0, NULL);
1173 CHECK_EQ(2, break_point_hit_count);
1174
1175 v8::Debug::SetDebugEventListener(NULL);
1176 CheckDebuggerUnloaded();
1177}
1178
1179
1180// Test that a break point can be set at an IC call location and survive a GC.
1181TEST(BreakPointConstructCallWithGC) {
1182 break_point_hit_count = 0;
1183 v8::HandleScope scope;
1184 DebugLocalContext env;
1185 v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage,
1186 v8::Undefined());
1187 v8::Script::Compile(v8::String::New("function bar(){ this.x = 1;}"))->Run();
1188 v8::Script::Compile(v8::String::New(
1189 "function foo(){return new bar(1).x;}"))->Run();
1190 v8::Local<v8::Function> foo =
1191 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1192
1193 // Run without breakpoints.
1194 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1195 CHECK_EQ(0, break_point_hit_count);
1196
1197 // Run with breakpoint.
1198 int bp = SetBreakPoint(foo, 0);
1199 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1200 CHECK_EQ(1, break_point_hit_count);
1201 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1202 CHECK_EQ(2, break_point_hit_count);
1203
1204 // Run without breakpoints.
1205 ClearBreakPoint(bp);
1206 foo->Call(env->Global(), 0, NULL);
1207 CHECK_EQ(2, break_point_hit_count);
1208
1209 v8::Debug::SetDebugEventListener(NULL);
1210 CheckDebuggerUnloaded();
1211}
1212
1213
Steve Blocka7e24c12009-10-30 11:49:00 +00001214// Test that a break point can be set at a return store location.
1215TEST(BreakPointReturn) {
1216 break_point_hit_count = 0;
1217 v8::HandleScope scope;
1218 DebugLocalContext env;
1219
1220 // Create a functions for checking the source line and column when hitting
1221 // a break point.
1222 frame_source_line = CompileFunction(&env,
1223 frame_source_line_source,
1224 "frame_source_line");
1225 frame_source_column = CompileFunction(&env,
1226 frame_source_column_source,
1227 "frame_source_column");
1228
1229
1230 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1231 v8::Undefined());
1232 v8::Script::Compile(v8::String::New("function foo(){}"))->Run();
1233 v8::Local<v8::Function> foo =
1234 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1235
1236 // Run without breakpoints.
1237 foo->Call(env->Global(), 0, NULL);
1238 CHECK_EQ(0, break_point_hit_count);
1239
1240 // Run with breakpoint
1241 int bp = SetBreakPoint(foo, 0);
1242 foo->Call(env->Global(), 0, NULL);
1243 CHECK_EQ(1, break_point_hit_count);
1244 CHECK_EQ(0, last_source_line);
Ben Murdochbb769b22010-08-11 14:56:33 +01001245 CHECK_EQ(15, last_source_column);
Steve Blocka7e24c12009-10-30 11:49:00 +00001246 foo->Call(env->Global(), 0, NULL);
1247 CHECK_EQ(2, break_point_hit_count);
1248 CHECK_EQ(0, last_source_line);
Ben Murdochbb769b22010-08-11 14:56:33 +01001249 CHECK_EQ(15, last_source_column);
Steve Blocka7e24c12009-10-30 11:49:00 +00001250
1251 // Run without breakpoints.
1252 ClearBreakPoint(bp);
1253 foo->Call(env->Global(), 0, NULL);
1254 CHECK_EQ(2, break_point_hit_count);
1255
1256 v8::Debug::SetDebugEventListener(NULL);
1257 CheckDebuggerUnloaded();
1258}
1259
1260
1261static void CallWithBreakPoints(v8::Local<v8::Object> recv,
1262 v8::Local<v8::Function> f,
1263 int break_point_count,
1264 int call_count) {
1265 break_point_hit_count = 0;
1266 for (int i = 0; i < call_count; i++) {
1267 f->Call(recv, 0, NULL);
1268 CHECK_EQ((i + 1) * break_point_count, break_point_hit_count);
1269 }
1270}
1271
1272// Test GC during break point processing.
1273TEST(GCDuringBreakPointProcessing) {
1274 break_point_hit_count = 0;
1275 v8::HandleScope scope;
1276 DebugLocalContext env;
1277
1278 v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage,
1279 v8::Undefined());
1280 v8::Local<v8::Function> foo;
1281
1282 // Test IC store break point with garbage collection.
1283 foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1284 SetBreakPoint(foo, 0);
1285 CallWithBreakPoints(env->Global(), foo, 1, 10);
1286
1287 // Test IC load break point with garbage collection.
1288 foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1289 SetBreakPoint(foo, 0);
1290 CallWithBreakPoints(env->Global(), foo, 1, 10);
1291
1292 // Test IC call break point with garbage collection.
1293 foo = CompileFunction(&env, "function bar(){};function foo(){bar();}", "foo");
1294 SetBreakPoint(foo, 0);
1295 CallWithBreakPoints(env->Global(), foo, 1, 10);
1296
1297 // Test return break point with garbage collection.
1298 foo = CompileFunction(&env, "function foo(){}", "foo");
1299 SetBreakPoint(foo, 0);
1300 CallWithBreakPoints(env->Global(), foo, 1, 25);
1301
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001302 // Test debug break slot break point with garbage collection.
1303 foo = CompileFunction(&env, "function foo(){var a;}", "foo");
1304 SetBreakPoint(foo, 0);
1305 CallWithBreakPoints(env->Global(), foo, 1, 25);
1306
Steve Blocka7e24c12009-10-30 11:49:00 +00001307 v8::Debug::SetDebugEventListener(NULL);
1308 CheckDebuggerUnloaded();
1309}
1310
1311
1312// Call the function three times with different garbage collections in between
1313// and make sure that the break point survives.
Ben Murdochbb769b22010-08-11 14:56:33 +01001314static void CallAndGC(v8::Local<v8::Object> recv,
1315 v8::Local<v8::Function> f,
1316 bool force_compaction) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001317 break_point_hit_count = 0;
1318
1319 for (int i = 0; i < 3; i++) {
1320 // Call function.
1321 f->Call(recv, 0, NULL);
1322 CHECK_EQ(1 + i * 3, break_point_hit_count);
1323
1324 // Scavenge and call function.
1325 Heap::CollectGarbage(0, v8::internal::NEW_SPACE);
1326 f->Call(recv, 0, NULL);
1327 CHECK_EQ(2 + i * 3, break_point_hit_count);
1328
1329 // Mark sweep (and perhaps compact) and call function.
Ben Murdochbb769b22010-08-11 14:56:33 +01001330 Heap::CollectAllGarbage(force_compaction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001331 f->Call(recv, 0, NULL);
1332 CHECK_EQ(3 + i * 3, break_point_hit_count);
1333 }
1334}
1335
1336
Ben Murdochbb769b22010-08-11 14:56:33 +01001337static void TestBreakPointSurviveGC(bool force_compaction) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001338 break_point_hit_count = 0;
1339 v8::HandleScope scope;
1340 DebugLocalContext env;
1341
1342 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1343 v8::Undefined());
1344 v8::Local<v8::Function> foo;
1345
1346 // Test IC store break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001347 {
1348 v8::Local<v8::Function> bar =
1349 CompileFunction(&env, "function foo(){}", "foo");
1350 foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1351 SetBreakPoint(foo, 0);
1352 }
1353 CallAndGC(env->Global(), foo, force_compaction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001354
1355 // Test IC load break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001356 {
1357 v8::Local<v8::Function> bar =
1358 CompileFunction(&env, "function foo(){}", "foo");
1359 foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1360 SetBreakPoint(foo, 0);
1361 }
1362 CallAndGC(env->Global(), foo, force_compaction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001363
1364 // Test IC call break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001365 {
1366 v8::Local<v8::Function> bar =
1367 CompileFunction(&env, "function foo(){}", "foo");
1368 foo = CompileFunction(&env,
1369 "function bar(){};function foo(){bar();}",
1370 "foo");
1371 SetBreakPoint(foo, 0);
1372 }
1373 CallAndGC(env->Global(), foo, force_compaction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001374
1375 // Test return break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001376 {
1377 v8::Local<v8::Function> bar =
1378 CompileFunction(&env, "function foo(){}", "foo");
1379 foo = CompileFunction(&env, "function foo(){}", "foo");
1380 SetBreakPoint(foo, 0);
1381 }
1382 CallAndGC(env->Global(), foo, force_compaction);
1383
1384 // Test non IC break point with garbage collection.
1385 {
1386 v8::Local<v8::Function> bar =
1387 CompileFunction(&env, "function foo(){}", "foo");
1388 foo = CompileFunction(&env, "function foo(){var bar=0;}", "foo");
1389 SetBreakPoint(foo, 0);
1390 }
1391 CallAndGC(env->Global(), foo, force_compaction);
1392
Steve Blocka7e24c12009-10-30 11:49:00 +00001393
1394 v8::Debug::SetDebugEventListener(NULL);
1395 CheckDebuggerUnloaded();
1396}
1397
1398
Ben Murdochbb769b22010-08-11 14:56:33 +01001399// Test that a break point can be set at a return store location.
1400TEST(BreakPointSurviveGC) {
1401 TestBreakPointSurviveGC(false);
1402 TestBreakPointSurviveGC(true);
1403}
1404
1405
Steve Blocka7e24c12009-10-30 11:49:00 +00001406// Test that break points can be set using the global Debug object.
1407TEST(BreakPointThroughJavaScript) {
1408 break_point_hit_count = 0;
1409 v8::HandleScope scope;
1410 DebugLocalContext env;
1411 env.ExposeDebug();
1412
1413 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1414 v8::Undefined());
1415 v8::Script::Compile(v8::String::New("function bar(){}"))->Run();
1416 v8::Script::Compile(v8::String::New("function foo(){bar();bar();}"))->Run();
1417 // 012345678901234567890
1418 // 1 2
1419 // Break points are set at position 3 and 9
1420 v8::Local<v8::Script> foo = v8::Script::Compile(v8::String::New("foo()"));
1421
1422 // Run without breakpoints.
1423 foo->Run();
1424 CHECK_EQ(0, break_point_hit_count);
1425
1426 // Run with one breakpoint
1427 int bp1 = SetBreakPointFromJS("foo", 0, 3);
1428 foo->Run();
1429 CHECK_EQ(1, break_point_hit_count);
1430 foo->Run();
1431 CHECK_EQ(2, break_point_hit_count);
1432
1433 // Run with two breakpoints
1434 int bp2 = SetBreakPointFromJS("foo", 0, 9);
1435 foo->Run();
1436 CHECK_EQ(4, break_point_hit_count);
1437 foo->Run();
1438 CHECK_EQ(6, break_point_hit_count);
1439
1440 // Run with one breakpoint
1441 ClearBreakPointFromJS(bp2);
1442 foo->Run();
1443 CHECK_EQ(7, break_point_hit_count);
1444 foo->Run();
1445 CHECK_EQ(8, break_point_hit_count);
1446
1447 // Run without breakpoints.
1448 ClearBreakPointFromJS(bp1);
1449 foo->Run();
1450 CHECK_EQ(8, break_point_hit_count);
1451
1452 v8::Debug::SetDebugEventListener(NULL);
1453 CheckDebuggerUnloaded();
1454
1455 // Make sure that the break point numbers are consecutive.
1456 CHECK_EQ(1, bp1);
1457 CHECK_EQ(2, bp2);
1458}
1459
1460
1461// Test that break points on scripts identified by name can be set using the
1462// global Debug object.
1463TEST(ScriptBreakPointByNameThroughJavaScript) {
1464 break_point_hit_count = 0;
1465 v8::HandleScope scope;
1466 DebugLocalContext env;
1467 env.ExposeDebug();
1468
1469 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1470 v8::Undefined());
1471
1472 v8::Local<v8::String> script = v8::String::New(
1473 "function f() {\n"
1474 " function h() {\n"
1475 " a = 0; // line 2\n"
1476 " }\n"
1477 " b = 1; // line 4\n"
1478 " return h();\n"
1479 "}\n"
1480 "\n"
1481 "function g() {\n"
1482 " function h() {\n"
1483 " a = 0;\n"
1484 " }\n"
1485 " b = 2; // line 12\n"
1486 " h();\n"
1487 " b = 3; // line 14\n"
1488 " f(); // line 15\n"
1489 "}");
1490
1491 // Compile the script and get the two functions.
1492 v8::ScriptOrigin origin =
1493 v8::ScriptOrigin(v8::String::New("test"));
1494 v8::Script::Compile(script, &origin)->Run();
1495 v8::Local<v8::Function> f =
1496 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1497 v8::Local<v8::Function> g =
1498 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
1499
1500 // Call f and g without break points.
1501 break_point_hit_count = 0;
1502 f->Call(env->Global(), 0, NULL);
1503 CHECK_EQ(0, break_point_hit_count);
1504 g->Call(env->Global(), 0, NULL);
1505 CHECK_EQ(0, break_point_hit_count);
1506
1507 // Call f and g with break point on line 12.
1508 int sbp1 = SetScriptBreakPointByNameFromJS("test", 12, 0);
1509 break_point_hit_count = 0;
1510 f->Call(env->Global(), 0, NULL);
1511 CHECK_EQ(0, break_point_hit_count);
1512 g->Call(env->Global(), 0, NULL);
1513 CHECK_EQ(1, break_point_hit_count);
1514
1515 // Remove the break point again.
1516 break_point_hit_count = 0;
1517 ClearBreakPointFromJS(sbp1);
1518 f->Call(env->Global(), 0, NULL);
1519 CHECK_EQ(0, break_point_hit_count);
1520 g->Call(env->Global(), 0, NULL);
1521 CHECK_EQ(0, break_point_hit_count);
1522
1523 // Call f and g with break point on line 2.
1524 int sbp2 = SetScriptBreakPointByNameFromJS("test", 2, 0);
1525 break_point_hit_count = 0;
1526 f->Call(env->Global(), 0, NULL);
1527 CHECK_EQ(1, break_point_hit_count);
1528 g->Call(env->Global(), 0, NULL);
1529 CHECK_EQ(2, break_point_hit_count);
1530
1531 // Call f and g with break point on line 2, 4, 12, 14 and 15.
1532 int sbp3 = SetScriptBreakPointByNameFromJS("test", 4, 0);
1533 int sbp4 = SetScriptBreakPointByNameFromJS("test", 12, 0);
1534 int sbp5 = SetScriptBreakPointByNameFromJS("test", 14, 0);
1535 int sbp6 = SetScriptBreakPointByNameFromJS("test", 15, 0);
1536 break_point_hit_count = 0;
1537 f->Call(env->Global(), 0, NULL);
1538 CHECK_EQ(2, break_point_hit_count);
1539 g->Call(env->Global(), 0, NULL);
1540 CHECK_EQ(7, break_point_hit_count);
1541
1542 // Remove all the break points again.
1543 break_point_hit_count = 0;
1544 ClearBreakPointFromJS(sbp2);
1545 ClearBreakPointFromJS(sbp3);
1546 ClearBreakPointFromJS(sbp4);
1547 ClearBreakPointFromJS(sbp5);
1548 ClearBreakPointFromJS(sbp6);
1549 f->Call(env->Global(), 0, NULL);
1550 CHECK_EQ(0, break_point_hit_count);
1551 g->Call(env->Global(), 0, NULL);
1552 CHECK_EQ(0, break_point_hit_count);
1553
1554 v8::Debug::SetDebugEventListener(NULL);
1555 CheckDebuggerUnloaded();
1556
1557 // Make sure that the break point numbers are consecutive.
1558 CHECK_EQ(1, sbp1);
1559 CHECK_EQ(2, sbp2);
1560 CHECK_EQ(3, sbp3);
1561 CHECK_EQ(4, sbp4);
1562 CHECK_EQ(5, sbp5);
1563 CHECK_EQ(6, sbp6);
1564}
1565
1566
1567TEST(ScriptBreakPointByIdThroughJavaScript) {
1568 break_point_hit_count = 0;
1569 v8::HandleScope scope;
1570 DebugLocalContext env;
1571 env.ExposeDebug();
1572
1573 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1574 v8::Undefined());
1575
1576 v8::Local<v8::String> source = v8::String::New(
1577 "function f() {\n"
1578 " function h() {\n"
1579 " a = 0; // line 2\n"
1580 " }\n"
1581 " b = 1; // line 4\n"
1582 " return h();\n"
1583 "}\n"
1584 "\n"
1585 "function g() {\n"
1586 " function h() {\n"
1587 " a = 0;\n"
1588 " }\n"
1589 " b = 2; // line 12\n"
1590 " h();\n"
1591 " b = 3; // line 14\n"
1592 " f(); // line 15\n"
1593 "}");
1594
1595 // Compile the script and get the two functions.
1596 v8::ScriptOrigin origin =
1597 v8::ScriptOrigin(v8::String::New("test"));
1598 v8::Local<v8::Script> script = v8::Script::Compile(source, &origin);
1599 script->Run();
1600 v8::Local<v8::Function> f =
1601 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1602 v8::Local<v8::Function> g =
1603 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
1604
1605 // Get the script id knowing that internally it is a 32 integer.
1606 uint32_t script_id = script->Id()->Uint32Value();
1607
1608 // Call f and g without break points.
1609 break_point_hit_count = 0;
1610 f->Call(env->Global(), 0, NULL);
1611 CHECK_EQ(0, break_point_hit_count);
1612 g->Call(env->Global(), 0, NULL);
1613 CHECK_EQ(0, break_point_hit_count);
1614
1615 // Call f and g with break point on line 12.
1616 int sbp1 = SetScriptBreakPointByIdFromJS(script_id, 12, 0);
1617 break_point_hit_count = 0;
1618 f->Call(env->Global(), 0, NULL);
1619 CHECK_EQ(0, break_point_hit_count);
1620 g->Call(env->Global(), 0, NULL);
1621 CHECK_EQ(1, break_point_hit_count);
1622
1623 // Remove the break point again.
1624 break_point_hit_count = 0;
1625 ClearBreakPointFromJS(sbp1);
1626 f->Call(env->Global(), 0, NULL);
1627 CHECK_EQ(0, break_point_hit_count);
1628 g->Call(env->Global(), 0, NULL);
1629 CHECK_EQ(0, break_point_hit_count);
1630
1631 // Call f and g with break point on line 2.
1632 int sbp2 = SetScriptBreakPointByIdFromJS(script_id, 2, 0);
1633 break_point_hit_count = 0;
1634 f->Call(env->Global(), 0, NULL);
1635 CHECK_EQ(1, break_point_hit_count);
1636 g->Call(env->Global(), 0, NULL);
1637 CHECK_EQ(2, break_point_hit_count);
1638
1639 // Call f and g with break point on line 2, 4, 12, 14 and 15.
1640 int sbp3 = SetScriptBreakPointByIdFromJS(script_id, 4, 0);
1641 int sbp4 = SetScriptBreakPointByIdFromJS(script_id, 12, 0);
1642 int sbp5 = SetScriptBreakPointByIdFromJS(script_id, 14, 0);
1643 int sbp6 = SetScriptBreakPointByIdFromJS(script_id, 15, 0);
1644 break_point_hit_count = 0;
1645 f->Call(env->Global(), 0, NULL);
1646 CHECK_EQ(2, break_point_hit_count);
1647 g->Call(env->Global(), 0, NULL);
1648 CHECK_EQ(7, break_point_hit_count);
1649
1650 // Remove all the break points again.
1651 break_point_hit_count = 0;
1652 ClearBreakPointFromJS(sbp2);
1653 ClearBreakPointFromJS(sbp3);
1654 ClearBreakPointFromJS(sbp4);
1655 ClearBreakPointFromJS(sbp5);
1656 ClearBreakPointFromJS(sbp6);
1657 f->Call(env->Global(), 0, NULL);
1658 CHECK_EQ(0, break_point_hit_count);
1659 g->Call(env->Global(), 0, NULL);
1660 CHECK_EQ(0, break_point_hit_count);
1661
1662 v8::Debug::SetDebugEventListener(NULL);
1663 CheckDebuggerUnloaded();
1664
1665 // Make sure that the break point numbers are consecutive.
1666 CHECK_EQ(1, sbp1);
1667 CHECK_EQ(2, sbp2);
1668 CHECK_EQ(3, sbp3);
1669 CHECK_EQ(4, sbp4);
1670 CHECK_EQ(5, sbp5);
1671 CHECK_EQ(6, sbp6);
1672}
1673
1674
1675// Test conditional script break points.
1676TEST(EnableDisableScriptBreakPoint) {
1677 break_point_hit_count = 0;
1678 v8::HandleScope scope;
1679 DebugLocalContext env;
1680 env.ExposeDebug();
1681
1682 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1683 v8::Undefined());
1684
1685 v8::Local<v8::String> script = v8::String::New(
1686 "function f() {\n"
1687 " a = 0; // line 1\n"
1688 "};");
1689
1690 // Compile the script and get function f.
1691 v8::ScriptOrigin origin =
1692 v8::ScriptOrigin(v8::String::New("test"));
1693 v8::Script::Compile(script, &origin)->Run();
1694 v8::Local<v8::Function> f =
1695 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1696
1697 // Set script break point on line 1 (in function f).
1698 int sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
1699
1700 // Call f while enabeling and disabling the script break point.
1701 break_point_hit_count = 0;
1702 f->Call(env->Global(), 0, NULL);
1703 CHECK_EQ(1, break_point_hit_count);
1704
1705 DisableScriptBreakPointFromJS(sbp);
1706 f->Call(env->Global(), 0, NULL);
1707 CHECK_EQ(1, break_point_hit_count);
1708
1709 EnableScriptBreakPointFromJS(sbp);
1710 f->Call(env->Global(), 0, NULL);
1711 CHECK_EQ(2, break_point_hit_count);
1712
1713 DisableScriptBreakPointFromJS(sbp);
1714 f->Call(env->Global(), 0, NULL);
1715 CHECK_EQ(2, break_point_hit_count);
1716
1717 // Reload the script and get f again checking that the disabeling survives.
1718 v8::Script::Compile(script, &origin)->Run();
1719 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1720 f->Call(env->Global(), 0, NULL);
1721 CHECK_EQ(2, break_point_hit_count);
1722
1723 EnableScriptBreakPointFromJS(sbp);
1724 f->Call(env->Global(), 0, NULL);
1725 CHECK_EQ(3, break_point_hit_count);
1726
1727 v8::Debug::SetDebugEventListener(NULL);
1728 CheckDebuggerUnloaded();
1729}
1730
1731
1732// Test conditional script break points.
1733TEST(ConditionalScriptBreakPoint) {
1734 break_point_hit_count = 0;
1735 v8::HandleScope scope;
1736 DebugLocalContext env;
1737 env.ExposeDebug();
1738
1739 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1740 v8::Undefined());
1741
1742 v8::Local<v8::String> script = v8::String::New(
1743 "count = 0;\n"
1744 "function f() {\n"
1745 " g(count++); // line 2\n"
1746 "};\n"
1747 "function g(x) {\n"
1748 " var a=x; // line 5\n"
1749 "};");
1750
1751 // Compile the script and get function f.
1752 v8::ScriptOrigin origin =
1753 v8::ScriptOrigin(v8::String::New("test"));
1754 v8::Script::Compile(script, &origin)->Run();
1755 v8::Local<v8::Function> f =
1756 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1757
1758 // Set script break point on line 5 (in function g).
1759 int sbp1 = SetScriptBreakPointByNameFromJS("test", 5, 0);
1760
1761 // Call f with different conditions on the script break point.
1762 break_point_hit_count = 0;
1763 ChangeScriptBreakPointConditionFromJS(sbp1, "false");
1764 f->Call(env->Global(), 0, NULL);
1765 CHECK_EQ(0, break_point_hit_count);
1766
1767 ChangeScriptBreakPointConditionFromJS(sbp1, "true");
1768 break_point_hit_count = 0;
1769 f->Call(env->Global(), 0, NULL);
1770 CHECK_EQ(1, break_point_hit_count);
1771
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001772 ChangeScriptBreakPointConditionFromJS(sbp1, "x % 2 == 0");
Steve Blocka7e24c12009-10-30 11:49:00 +00001773 break_point_hit_count = 0;
1774 for (int i = 0; i < 10; i++) {
1775 f->Call(env->Global(), 0, NULL);
1776 }
1777 CHECK_EQ(5, break_point_hit_count);
1778
1779 // Reload the script and get f again checking that the condition survives.
1780 v8::Script::Compile(script, &origin)->Run();
1781 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1782
1783 break_point_hit_count = 0;
1784 for (int i = 0; i < 10; i++) {
1785 f->Call(env->Global(), 0, NULL);
1786 }
1787 CHECK_EQ(5, break_point_hit_count);
1788
1789 v8::Debug::SetDebugEventListener(NULL);
1790 CheckDebuggerUnloaded();
1791}
1792
1793
1794// Test ignore count on script break points.
1795TEST(ScriptBreakPointIgnoreCount) {
1796 break_point_hit_count = 0;
1797 v8::HandleScope scope;
1798 DebugLocalContext env;
1799 env.ExposeDebug();
1800
1801 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1802 v8::Undefined());
1803
1804 v8::Local<v8::String> script = v8::String::New(
1805 "function f() {\n"
1806 " a = 0; // line 1\n"
1807 "};");
1808
1809 // Compile the script and get function f.
1810 v8::ScriptOrigin origin =
1811 v8::ScriptOrigin(v8::String::New("test"));
1812 v8::Script::Compile(script, &origin)->Run();
1813 v8::Local<v8::Function> f =
1814 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1815
1816 // Set script break point on line 1 (in function f).
1817 int sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
1818
1819 // Call f with different ignores on the script break point.
1820 break_point_hit_count = 0;
1821 ChangeScriptBreakPointIgnoreCountFromJS(sbp, 1);
1822 f->Call(env->Global(), 0, NULL);
1823 CHECK_EQ(0, break_point_hit_count);
1824 f->Call(env->Global(), 0, NULL);
1825 CHECK_EQ(1, break_point_hit_count);
1826
1827 ChangeScriptBreakPointIgnoreCountFromJS(sbp, 5);
1828 break_point_hit_count = 0;
1829 for (int i = 0; i < 10; i++) {
1830 f->Call(env->Global(), 0, NULL);
1831 }
1832 CHECK_EQ(5, break_point_hit_count);
1833
1834 // Reload the script and get f again checking that the ignore survives.
1835 v8::Script::Compile(script, &origin)->Run();
1836 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1837
1838 break_point_hit_count = 0;
1839 for (int i = 0; i < 10; i++) {
1840 f->Call(env->Global(), 0, NULL);
1841 }
1842 CHECK_EQ(5, break_point_hit_count);
1843
1844 v8::Debug::SetDebugEventListener(NULL);
1845 CheckDebuggerUnloaded();
1846}
1847
1848
1849// Test that script break points survive when a script is reloaded.
1850TEST(ScriptBreakPointReload) {
1851 break_point_hit_count = 0;
1852 v8::HandleScope scope;
1853 DebugLocalContext env;
1854 env.ExposeDebug();
1855
1856 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1857 v8::Undefined());
1858
1859 v8::Local<v8::Function> f;
1860 v8::Local<v8::String> script = v8::String::New(
1861 "function f() {\n"
1862 " function h() {\n"
1863 " a = 0; // line 2\n"
1864 " }\n"
1865 " b = 1; // line 4\n"
1866 " return h();\n"
1867 "}");
1868
1869 v8::ScriptOrigin origin_1 = v8::ScriptOrigin(v8::String::New("1"));
1870 v8::ScriptOrigin origin_2 = v8::ScriptOrigin(v8::String::New("2"));
1871
1872 // Set a script break point before the script is loaded.
1873 SetScriptBreakPointByNameFromJS("1", 2, 0);
1874
1875 // Compile the script and get the function.
1876 v8::Script::Compile(script, &origin_1)->Run();
1877 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
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 // Compile the script again with a different script data and get the
1885 // function.
1886 v8::Script::Compile(script, &origin_2)->Run();
1887 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1888
1889 // Call f and check that no break points are set.
1890 break_point_hit_count = 0;
1891 f->Call(env->Global(), 0, NULL);
1892 CHECK_EQ(0, break_point_hit_count);
1893
1894 // Compile the script again and get the function.
1895 v8::Script::Compile(script, &origin_1)->Run();
1896 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1897
1898 // Call f and check that the script break point is active.
1899 break_point_hit_count = 0;
1900 f->Call(env->Global(), 0, NULL);
1901 CHECK_EQ(1, break_point_hit_count);
1902
1903 v8::Debug::SetDebugEventListener(NULL);
1904 CheckDebuggerUnloaded();
1905}
1906
1907
1908// Test when several scripts has the same script data
1909TEST(ScriptBreakPointMultiple) {
1910 break_point_hit_count = 0;
1911 v8::HandleScope scope;
1912 DebugLocalContext env;
1913 env.ExposeDebug();
1914
1915 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1916 v8::Undefined());
1917
1918 v8::Local<v8::Function> f;
1919 v8::Local<v8::String> script_f = v8::String::New(
1920 "function f() {\n"
1921 " a = 0; // line 1\n"
1922 "}");
1923
1924 v8::Local<v8::Function> g;
1925 v8::Local<v8::String> script_g = v8::String::New(
1926 "function g() {\n"
1927 " b = 0; // line 1\n"
1928 "}");
1929
1930 v8::ScriptOrigin origin =
1931 v8::ScriptOrigin(v8::String::New("test"));
1932
1933 // Set a script break point before the scripts are loaded.
1934 int sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
1935
1936 // Compile the scripts with same script data and get the functions.
1937 v8::Script::Compile(script_f, &origin)->Run();
1938 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1939 v8::Script::Compile(script_g, &origin)->Run();
1940 g = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
1941
1942 // Call f and g and check that the script break point is active.
1943 break_point_hit_count = 0;
1944 f->Call(env->Global(), 0, NULL);
1945 CHECK_EQ(1, break_point_hit_count);
1946 g->Call(env->Global(), 0, NULL);
1947 CHECK_EQ(2, break_point_hit_count);
1948
1949 // Clear the script break point.
1950 ClearBreakPointFromJS(sbp);
1951
1952 // Call f and g and check that the script break point is no longer active.
1953 break_point_hit_count = 0;
1954 f->Call(env->Global(), 0, NULL);
1955 CHECK_EQ(0, break_point_hit_count);
1956 g->Call(env->Global(), 0, NULL);
1957 CHECK_EQ(0, break_point_hit_count);
1958
1959 // Set script break point with the scripts loaded.
1960 sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
1961
1962 // Call f and g and check that the script break point is active.
1963 break_point_hit_count = 0;
1964 f->Call(env->Global(), 0, NULL);
1965 CHECK_EQ(1, break_point_hit_count);
1966 g->Call(env->Global(), 0, NULL);
1967 CHECK_EQ(2, break_point_hit_count);
1968
1969 v8::Debug::SetDebugEventListener(NULL);
1970 CheckDebuggerUnloaded();
1971}
1972
1973
1974// Test the script origin which has both name and line offset.
1975TEST(ScriptBreakPointLineOffset) {
1976 break_point_hit_count = 0;
1977 v8::HandleScope scope;
1978 DebugLocalContext env;
1979 env.ExposeDebug();
1980
1981 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1982 v8::Undefined());
1983
1984 v8::Local<v8::Function> f;
1985 v8::Local<v8::String> script = v8::String::New(
1986 "function f() {\n"
1987 " a = 0; // line 8 as this script has line offset 7\n"
1988 " b = 0; // line 9 as this script has line offset 7\n"
1989 "}");
1990
1991 // Create script origin both name and line offset.
1992 v8::ScriptOrigin origin(v8::String::New("test.html"),
1993 v8::Integer::New(7));
1994
1995 // Set two script break points before the script is loaded.
1996 int sbp1 = SetScriptBreakPointByNameFromJS("test.html", 8, 0);
1997 int sbp2 = SetScriptBreakPointByNameFromJS("test.html", 9, 0);
1998
1999 // Compile the script and get the function.
2000 v8::Script::Compile(script, &origin)->Run();
2001 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2002
2003 // Call f and check that the script break point is active.
2004 break_point_hit_count = 0;
2005 f->Call(env->Global(), 0, NULL);
2006 CHECK_EQ(2, break_point_hit_count);
2007
2008 // Clear the script break points.
2009 ClearBreakPointFromJS(sbp1);
2010 ClearBreakPointFromJS(sbp2);
2011
2012 // Call f and check that no script break points are active.
2013 break_point_hit_count = 0;
2014 f->Call(env->Global(), 0, NULL);
2015 CHECK_EQ(0, break_point_hit_count);
2016
2017 // Set a script break point with the script loaded.
2018 sbp1 = SetScriptBreakPointByNameFromJS("test.html", 9, 0);
2019
2020 // Call f and check that the script break point is active.
2021 break_point_hit_count = 0;
2022 f->Call(env->Global(), 0, NULL);
2023 CHECK_EQ(1, break_point_hit_count);
2024
2025 v8::Debug::SetDebugEventListener(NULL);
2026 CheckDebuggerUnloaded();
2027}
2028
2029
2030// Test script break points set on lines.
2031TEST(ScriptBreakPointLine) {
2032 v8::HandleScope scope;
2033 DebugLocalContext env;
2034 env.ExposeDebug();
2035
2036 // Create a function for checking the function when hitting a break point.
2037 frame_function_name = CompileFunction(&env,
2038 frame_function_name_source,
2039 "frame_function_name");
2040
2041 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2042 v8::Undefined());
2043
2044 v8::Local<v8::Function> f;
2045 v8::Local<v8::Function> g;
2046 v8::Local<v8::String> script = v8::String::New(
2047 "a = 0 // line 0\n"
2048 "function f() {\n"
2049 " a = 1; // line 2\n"
2050 "}\n"
2051 " a = 2; // line 4\n"
2052 " /* xx */ function g() { // line 5\n"
2053 " function h() { // line 6\n"
2054 " a = 3; // line 7\n"
2055 " }\n"
2056 " h(); // line 9\n"
2057 " a = 4; // line 10\n"
2058 " }\n"
2059 " a=5; // line 12");
2060
2061 // Set a couple script break point before the script is loaded.
2062 int sbp1 = SetScriptBreakPointByNameFromJS("test.html", 0, -1);
2063 int sbp2 = SetScriptBreakPointByNameFromJS("test.html", 1, -1);
2064 int sbp3 = SetScriptBreakPointByNameFromJS("test.html", 5, -1);
2065
2066 // Compile the script and get the function.
2067 break_point_hit_count = 0;
2068 v8::ScriptOrigin origin(v8::String::New("test.html"), v8::Integer::New(0));
2069 v8::Script::Compile(script, &origin)->Run();
2070 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2071 g = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
2072
2073 // Chesk that a break point was hit when the script was run.
2074 CHECK_EQ(1, break_point_hit_count);
Steve Blockd0582a62009-12-15 09:54:21 +00002075 CHECK_EQ(0, StrLength(last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00002076
2077 // Call f and check that the script break point.
2078 f->Call(env->Global(), 0, NULL);
2079 CHECK_EQ(2, break_point_hit_count);
2080 CHECK_EQ("f", last_function_hit);
2081
2082 // Call g and check that the script break point.
2083 g->Call(env->Global(), 0, NULL);
2084 CHECK_EQ(3, break_point_hit_count);
2085 CHECK_EQ("g", last_function_hit);
2086
2087 // Clear the script break point on g and set one on h.
2088 ClearBreakPointFromJS(sbp3);
2089 int sbp4 = SetScriptBreakPointByNameFromJS("test.html", 6, -1);
2090
2091 // Call g and check that the script break point in h is hit.
2092 g->Call(env->Global(), 0, NULL);
2093 CHECK_EQ(4, break_point_hit_count);
2094 CHECK_EQ("h", last_function_hit);
2095
2096 // Clear break points in f and h. Set a new one in the script between
2097 // functions f and g and test that there is no break points in f and g any
2098 // more.
2099 ClearBreakPointFromJS(sbp2);
2100 ClearBreakPointFromJS(sbp4);
2101 int sbp5 = SetScriptBreakPointByNameFromJS("test.html", 4, -1);
2102 break_point_hit_count = 0;
2103 f->Call(env->Global(), 0, NULL);
2104 g->Call(env->Global(), 0, NULL);
2105 CHECK_EQ(0, break_point_hit_count);
2106
2107 // Reload the script which should hit two break points.
2108 break_point_hit_count = 0;
2109 v8::Script::Compile(script, &origin)->Run();
2110 CHECK_EQ(2, break_point_hit_count);
Steve Blockd0582a62009-12-15 09:54:21 +00002111 CHECK_EQ(0, StrLength(last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00002112
2113 // Set a break point in the code after the last function decleration.
2114 int sbp6 = SetScriptBreakPointByNameFromJS("test.html", 12, -1);
2115
2116 // Reload the script which should hit three break points.
2117 break_point_hit_count = 0;
2118 v8::Script::Compile(script, &origin)->Run();
2119 CHECK_EQ(3, break_point_hit_count);
Steve Blockd0582a62009-12-15 09:54:21 +00002120 CHECK_EQ(0, StrLength(last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00002121
2122 // Clear the last break points, and reload the script which should not hit any
2123 // break points.
2124 ClearBreakPointFromJS(sbp1);
2125 ClearBreakPointFromJS(sbp5);
2126 ClearBreakPointFromJS(sbp6);
2127 break_point_hit_count = 0;
2128 v8::Script::Compile(script, &origin)->Run();
2129 CHECK_EQ(0, break_point_hit_count);
2130
2131 v8::Debug::SetDebugEventListener(NULL);
2132 CheckDebuggerUnloaded();
2133}
2134
2135
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002136// Test top level script break points set on lines.
2137TEST(ScriptBreakPointLineTopLevel) {
2138 v8::HandleScope scope;
2139 DebugLocalContext env;
2140 env.ExposeDebug();
2141
2142 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2143 v8::Undefined());
2144
2145 v8::Local<v8::String> script = v8::String::New(
2146 "function f() {\n"
2147 " a = 1; // line 1\n"
2148 "}\n"
2149 "a = 2; // line 3\n");
2150 v8::Local<v8::Function> f;
2151 {
2152 v8::HandleScope scope;
2153 v8::Script::Compile(script, v8::String::New("test.html"))->Run();
2154 }
2155 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2156
2157 Heap::CollectAllGarbage(false);
2158
2159 SetScriptBreakPointByNameFromJS("test.html", 3, -1);
2160
2161 // Call f and check that there was no break points.
2162 break_point_hit_count = 0;
2163 f->Call(env->Global(), 0, NULL);
2164 CHECK_EQ(0, break_point_hit_count);
2165
2166 // Recompile and run script and check that break point was hit.
2167 break_point_hit_count = 0;
2168 v8::Script::Compile(script, v8::String::New("test.html"))->Run();
2169 CHECK_EQ(1, break_point_hit_count);
2170
2171 // Call f and check that there are still no break points.
2172 break_point_hit_count = 0;
2173 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2174 CHECK_EQ(0, break_point_hit_count);
2175
2176 v8::Debug::SetDebugEventListener(NULL);
2177 CheckDebuggerUnloaded();
2178}
2179
2180
Steve Block8defd9f2010-07-08 12:39:36 +01002181// Test that it is possible to add and remove break points in a top level
2182// function which has no references but has not been collected yet.
2183TEST(ScriptBreakPointTopLevelCrash) {
2184 v8::HandleScope scope;
2185 DebugLocalContext env;
2186 env.ExposeDebug();
2187
2188 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2189 v8::Undefined());
2190
2191 v8::Local<v8::String> script_source = v8::String::New(
2192 "function f() {\n"
2193 " return 0;\n"
2194 "}\n"
2195 "f()");
2196
2197 int sbp1 = SetScriptBreakPointByNameFromJS("test.html", 3, -1);
2198 {
2199 v8::HandleScope scope;
2200 break_point_hit_count = 0;
2201 v8::Script::Compile(script_source, v8::String::New("test.html"))->Run();
2202 CHECK_EQ(1, break_point_hit_count);
2203 }
2204
2205 int sbp2 = SetScriptBreakPointByNameFromJS("test.html", 3, -1);
2206 ClearBreakPointFromJS(sbp1);
2207 ClearBreakPointFromJS(sbp2);
2208
2209 v8::Debug::SetDebugEventListener(NULL);
2210 CheckDebuggerUnloaded();
2211}
2212
2213
Steve Blocka7e24c12009-10-30 11:49:00 +00002214// Test that it is possible to remove the last break point for a function
2215// inside the break handling of that break point.
2216TEST(RemoveBreakPointInBreak) {
2217 v8::HandleScope scope;
2218 DebugLocalContext env;
2219
2220 v8::Local<v8::Function> foo =
2221 CompileFunction(&env, "function foo(){a=1;}", "foo");
2222 debug_event_remove_break_point = SetBreakPoint(foo, 0);
2223
2224 // Register the debug event listener pasing the function
2225 v8::Debug::SetDebugEventListener(DebugEventRemoveBreakPoint, foo);
2226
2227 break_point_hit_count = 0;
2228 foo->Call(env->Global(), 0, NULL);
2229 CHECK_EQ(1, break_point_hit_count);
2230
2231 break_point_hit_count = 0;
2232 foo->Call(env->Global(), 0, NULL);
2233 CHECK_EQ(0, break_point_hit_count);
2234
2235 v8::Debug::SetDebugEventListener(NULL);
2236 CheckDebuggerUnloaded();
2237}
2238
2239
2240// Test that the debugger statement causes a break.
2241TEST(DebuggerStatement) {
2242 break_point_hit_count = 0;
2243 v8::HandleScope scope;
2244 DebugLocalContext env;
2245 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2246 v8::Undefined());
2247 v8::Script::Compile(v8::String::New("function bar(){debugger}"))->Run();
2248 v8::Script::Compile(v8::String::New(
2249 "function foo(){debugger;debugger;}"))->Run();
2250 v8::Local<v8::Function> foo =
2251 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
2252 v8::Local<v8::Function> bar =
2253 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("bar")));
2254
2255 // Run function with debugger statement
2256 bar->Call(env->Global(), 0, NULL);
2257 CHECK_EQ(1, break_point_hit_count);
2258
2259 // Run function with two debugger statement
2260 foo->Call(env->Global(), 0, NULL);
2261 CHECK_EQ(3, break_point_hit_count);
2262
2263 v8::Debug::SetDebugEventListener(NULL);
2264 CheckDebuggerUnloaded();
2265}
2266
2267
Steve Block8defd9f2010-07-08 12:39:36 +01002268// Test setting a breakpoint on the debugger statement.
Leon Clarke4515c472010-02-03 11:58:03 +00002269TEST(DebuggerStatementBreakpoint) {
2270 break_point_hit_count = 0;
2271 v8::HandleScope scope;
2272 DebugLocalContext env;
2273 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2274 v8::Undefined());
2275 v8::Script::Compile(v8::String::New("function foo(){debugger;}"))->Run();
2276 v8::Local<v8::Function> foo =
2277 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
2278
2279 // The debugger statement triggers breakpint hit
2280 foo->Call(env->Global(), 0, NULL);
2281 CHECK_EQ(1, break_point_hit_count);
2282
2283 int bp = SetBreakPoint(foo, 0);
2284
2285 // Set breakpoint does not duplicate hits
2286 foo->Call(env->Global(), 0, NULL);
2287 CHECK_EQ(2, break_point_hit_count);
2288
2289 ClearBreakPoint(bp);
2290 v8::Debug::SetDebugEventListener(NULL);
2291 CheckDebuggerUnloaded();
2292}
2293
2294
Steve Blocka7e24c12009-10-30 11:49:00 +00002295// Thest that the evaluation of expressions when a break point is hit generates
2296// the correct results.
2297TEST(DebugEvaluate) {
2298 v8::HandleScope scope;
2299 DebugLocalContext env;
2300 env.ExposeDebug();
2301
2302 // Create a function for checking the evaluation when hitting a break point.
2303 evaluate_check_function = CompileFunction(&env,
2304 evaluate_check_source,
2305 "evaluate_check");
2306 // Register the debug event listener
2307 v8::Debug::SetDebugEventListener(DebugEventEvaluate);
2308
2309 // Different expected vaules of x and a when in a break point (u = undefined,
2310 // d = Hello, world!).
2311 struct EvaluateCheck checks_uu[] = {
2312 {"x", v8::Undefined()},
2313 {"a", v8::Undefined()},
2314 {NULL, v8::Handle<v8::Value>()}
2315 };
2316 struct EvaluateCheck checks_hu[] = {
2317 {"x", v8::String::New("Hello, world!")},
2318 {"a", v8::Undefined()},
2319 {NULL, v8::Handle<v8::Value>()}
2320 };
2321 struct EvaluateCheck checks_hh[] = {
2322 {"x", v8::String::New("Hello, world!")},
2323 {"a", v8::String::New("Hello, world!")},
2324 {NULL, v8::Handle<v8::Value>()}
2325 };
2326
2327 // Simple test function. The "y=0" is in the function foo to provide a break
2328 // location. For "y=0" the "y" is at position 15 in the barbar function
2329 // therefore setting breakpoint at position 15 will break at "y=0" and
2330 // setting it higher will break after.
2331 v8::Local<v8::Function> foo = CompileFunction(&env,
2332 "function foo(x) {"
2333 " var a;"
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002334 " y=0;" // To ensure break location 1.
Steve Blocka7e24c12009-10-30 11:49:00 +00002335 " a=x;"
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002336 " y=0;" // To ensure break location 2.
Steve Blocka7e24c12009-10-30 11:49:00 +00002337 "}",
2338 "foo");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002339 const int foo_break_position_1 = 15;
2340 const int foo_break_position_2 = 29;
Steve Blocka7e24c12009-10-30 11:49:00 +00002341
2342 // Arguments with one parameter "Hello, world!"
2343 v8::Handle<v8::Value> argv_foo[1] = { v8::String::New("Hello, world!") };
2344
2345 // Call foo with breakpoint set before a=x and undefined as parameter.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002346 int bp = SetBreakPoint(foo, foo_break_position_1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002347 checks = checks_uu;
2348 foo->Call(env->Global(), 0, NULL);
2349
2350 // Call foo with breakpoint set before a=x and parameter "Hello, world!".
2351 checks = checks_hu;
2352 foo->Call(env->Global(), 1, argv_foo);
2353
2354 // Call foo with breakpoint set after a=x and parameter "Hello, world!".
2355 ClearBreakPoint(bp);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002356 SetBreakPoint(foo, foo_break_position_2);
Steve Blocka7e24c12009-10-30 11:49:00 +00002357 checks = checks_hh;
2358 foo->Call(env->Global(), 1, argv_foo);
2359
2360 // Test function with an inner function. The "y=0" is in function barbar
2361 // to provide a break location. For "y=0" the "y" is at position 8 in the
2362 // barbar function therefore setting breakpoint at position 8 will break at
2363 // "y=0" and setting it higher will break after.
2364 v8::Local<v8::Function> bar = CompileFunction(&env,
2365 "y = 0;"
2366 "x = 'Goodbye, world!';"
2367 "function bar(x, b) {"
2368 " var a;"
2369 " function barbar() {"
2370 " y=0; /* To ensure break location.*/"
2371 " a=x;"
2372 " };"
2373 " debug.Debug.clearAllBreakPoints();"
2374 " barbar();"
2375 " y=0;a=x;"
2376 "}",
2377 "bar");
2378 const int barbar_break_position = 8;
2379
2380 // Call bar setting breakpoint before a=x in barbar and undefined as
2381 // parameter.
2382 checks = checks_uu;
2383 v8::Handle<v8::Value> argv_bar_1[2] = {
2384 v8::Undefined(),
2385 v8::Number::New(barbar_break_position)
2386 };
2387 bar->Call(env->Global(), 2, argv_bar_1);
2388
2389 // Call bar setting breakpoint before a=x in barbar and parameter
2390 // "Hello, world!".
2391 checks = checks_hu;
2392 v8::Handle<v8::Value> argv_bar_2[2] = {
2393 v8::String::New("Hello, world!"),
2394 v8::Number::New(barbar_break_position)
2395 };
2396 bar->Call(env->Global(), 2, argv_bar_2);
2397
2398 // Call bar setting breakpoint after a=x in barbar and parameter
2399 // "Hello, world!".
2400 checks = checks_hh;
2401 v8::Handle<v8::Value> argv_bar_3[2] = {
2402 v8::String::New("Hello, world!"),
2403 v8::Number::New(barbar_break_position + 1)
2404 };
2405 bar->Call(env->Global(), 2, argv_bar_3);
2406
2407 v8::Debug::SetDebugEventListener(NULL);
2408 CheckDebuggerUnloaded();
2409}
2410
Leon Clarkee46be812010-01-19 14:06:41 +00002411// Copies a C string to a 16-bit string. Does not check for buffer overflow.
2412// Does not use the V8 engine to convert strings, so it can be used
2413// in any thread. Returns the length of the string.
2414int AsciiToUtf16(const char* input_buffer, uint16_t* output_buffer) {
2415 int i;
2416 for (i = 0; input_buffer[i] != '\0'; ++i) {
2417 // ASCII does not use chars > 127, but be careful anyway.
2418 output_buffer[i] = static_cast<unsigned char>(input_buffer[i]);
2419 }
2420 output_buffer[i] = 0;
2421 return i;
2422}
2423
2424// Copies a 16-bit string to a C string by dropping the high byte of
2425// each character. Does not check for buffer overflow.
2426// Can be used in any thread. Requires string length as an input.
2427int Utf16ToAscii(const uint16_t* input_buffer, int length,
2428 char* output_buffer, int output_len = -1) {
2429 if (output_len >= 0) {
2430 if (length > output_len - 1) {
2431 length = output_len - 1;
2432 }
2433 }
2434
2435 for (int i = 0; i < length; ++i) {
2436 output_buffer[i] = static_cast<char>(input_buffer[i]);
2437 }
2438 output_buffer[length] = '\0';
2439 return length;
2440}
2441
2442
2443// We match parts of the message to get evaluate result int value.
2444bool GetEvaluateStringResult(char *message, char* buffer, int buffer_size) {
Leon Clarked91b9f72010-01-27 17:25:45 +00002445 if (strstr(message, "\"command\":\"evaluate\"") == NULL) {
2446 return false;
2447 }
2448 const char* prefix = "\"text\":\"";
2449 char* pos1 = strstr(message, prefix);
2450 if (pos1 == NULL) {
2451 return false;
2452 }
2453 pos1 += strlen(prefix);
2454 char* pos2 = strchr(pos1, '"');
2455 if (pos2 == NULL) {
Leon Clarkee46be812010-01-19 14:06:41 +00002456 return false;
2457 }
2458 Vector<char> buf(buffer, buffer_size);
Leon Clarked91b9f72010-01-27 17:25:45 +00002459 int len = static_cast<int>(pos2 - pos1);
2460 if (len > buffer_size - 1) {
2461 len = buffer_size - 1;
2462 }
2463 OS::StrNCpy(buf, pos1, len);
Leon Clarkee46be812010-01-19 14:06:41 +00002464 buffer[buffer_size - 1] = '\0';
2465 return true;
2466}
2467
2468
2469struct EvaluateResult {
2470 static const int kBufferSize = 20;
2471 char buffer[kBufferSize];
2472};
2473
2474struct DebugProcessDebugMessagesData {
2475 static const int kArraySize = 5;
2476 int counter;
2477 EvaluateResult results[kArraySize];
2478
2479 void reset() {
2480 counter = 0;
2481 }
2482 EvaluateResult* current() {
2483 return &results[counter % kArraySize];
2484 }
2485 void next() {
2486 counter++;
2487 }
2488};
2489
2490DebugProcessDebugMessagesData process_debug_messages_data;
2491
2492static void DebugProcessDebugMessagesHandler(
2493 const uint16_t* message,
2494 int length,
2495 v8::Debug::ClientData* client_data) {
2496
2497 const int kBufferSize = 100000;
2498 char print_buffer[kBufferSize];
2499 Utf16ToAscii(message, length, print_buffer, kBufferSize);
2500
2501 EvaluateResult* array_item = process_debug_messages_data.current();
2502
2503 bool res = GetEvaluateStringResult(print_buffer,
2504 array_item->buffer,
2505 EvaluateResult::kBufferSize);
2506 if (res) {
2507 process_debug_messages_data.next();
2508 }
2509}
2510
2511// Test that the evaluation of expressions works even from ProcessDebugMessages
2512// i.e. with empty stack.
2513TEST(DebugEvaluateWithoutStack) {
2514 v8::Debug::SetMessageHandler(DebugProcessDebugMessagesHandler);
2515
2516 v8::HandleScope scope;
2517 DebugLocalContext env;
2518
2519 const char* source =
2520 "var v1 = 'Pinguin';\n function getAnimal() { return 'Capy' + 'bara'; }";
2521
2522 v8::Script::Compile(v8::String::New(source))->Run();
2523
2524 v8::Debug::ProcessDebugMessages();
2525
2526 const int kBufferSize = 1000;
2527 uint16_t buffer[kBufferSize];
2528
2529 const char* command_111 = "{\"seq\":111,"
2530 "\"type\":\"request\","
2531 "\"command\":\"evaluate\","
2532 "\"arguments\":{"
2533 " \"global\":true,"
2534 " \"expression\":\"v1\",\"disable_break\":true"
2535 "}}";
2536
2537 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_111, buffer));
2538
2539 const char* command_112 = "{\"seq\":112,"
2540 "\"type\":\"request\","
2541 "\"command\":\"evaluate\","
2542 "\"arguments\":{"
2543 " \"global\":true,"
2544 " \"expression\":\"getAnimal()\",\"disable_break\":true"
2545 "}}";
2546
2547 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_112, buffer));
2548
2549 const char* command_113 = "{\"seq\":113,"
2550 "\"type\":\"request\","
2551 "\"command\":\"evaluate\","
2552 "\"arguments\":{"
2553 " \"global\":true,"
2554 " \"expression\":\"239 + 566\",\"disable_break\":true"
2555 "}}";
2556
2557 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_113, buffer));
2558
2559 v8::Debug::ProcessDebugMessages();
2560
2561 CHECK_EQ(3, process_debug_messages_data.counter);
2562
Leon Clarked91b9f72010-01-27 17:25:45 +00002563 CHECK_EQ(strcmp("Pinguin", process_debug_messages_data.results[0].buffer), 0);
2564 CHECK_EQ(strcmp("Capybara", process_debug_messages_data.results[1].buffer),
2565 0);
2566 CHECK_EQ(strcmp("805", process_debug_messages_data.results[2].buffer), 0);
Leon Clarkee46be812010-01-19 14:06:41 +00002567
2568 v8::Debug::SetMessageHandler(NULL);
2569 v8::Debug::SetDebugEventListener(NULL);
2570 CheckDebuggerUnloaded();
2571}
2572
Steve Blocka7e24c12009-10-30 11:49:00 +00002573
2574// Simple test of the stepping mechanism using only store ICs.
2575TEST(DebugStepLinear) {
2576 v8::HandleScope scope;
2577 DebugLocalContext env;
2578
2579 // Create a function for testing stepping.
2580 v8::Local<v8::Function> foo = CompileFunction(&env,
2581 "function foo(){a=1;b=1;c=1;}",
2582 "foo");
2583 SetBreakPoint(foo, 3);
2584
2585 // Register a debug event listener which steps and counts.
2586 v8::Debug::SetDebugEventListener(DebugEventStep);
2587
2588 step_action = StepIn;
2589 break_point_hit_count = 0;
2590 foo->Call(env->Global(), 0, NULL);
2591
2592 // With stepping all break locations are hit.
2593 CHECK_EQ(4, break_point_hit_count);
2594
2595 v8::Debug::SetDebugEventListener(NULL);
2596 CheckDebuggerUnloaded();
2597
2598 // Register a debug event listener which just counts.
2599 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2600
2601 SetBreakPoint(foo, 3);
2602 break_point_hit_count = 0;
2603 foo->Call(env->Global(), 0, NULL);
2604
2605 // Without stepping only active break points are hit.
2606 CHECK_EQ(1, break_point_hit_count);
2607
2608 v8::Debug::SetDebugEventListener(NULL);
2609 CheckDebuggerUnloaded();
2610}
2611
2612
2613// Test of the stepping mechanism for keyed load in a loop.
2614TEST(DebugStepKeyedLoadLoop) {
2615 v8::HandleScope scope;
2616 DebugLocalContext env;
2617
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002618 // Register a debug event listener which steps and counts.
2619 v8::Debug::SetDebugEventListener(DebugEventStep);
2620
Steve Blocka7e24c12009-10-30 11:49:00 +00002621 // Create a function for testing stepping of keyed load. The statement 'y=1'
2622 // is there to have more than one breakable statement in the loop, TODO(315).
2623 v8::Local<v8::Function> foo = CompileFunction(
2624 &env,
2625 "function foo(a) {\n"
2626 " var x;\n"
2627 " var len = a.length;\n"
2628 " for (var i = 0; i < len; i++) {\n"
2629 " y = 1;\n"
2630 " x = a[i];\n"
2631 " }\n"
2632 "}\n",
2633 "foo");
2634
2635 // Create array [0,1,2,3,4,5,6,7,8,9]
2636 v8::Local<v8::Array> a = v8::Array::New(10);
2637 for (int i = 0; i < 10; i++) {
2638 a->Set(v8::Number::New(i), v8::Number::New(i));
2639 }
2640
2641 // Call function without any break points to ensure inlining is in place.
2642 const int kArgc = 1;
2643 v8::Handle<v8::Value> args[kArgc] = { a };
2644 foo->Call(env->Global(), kArgc, args);
2645
Steve Blocka7e24c12009-10-30 11:49:00 +00002646 // Setup break point and step through the function.
2647 SetBreakPoint(foo, 3);
2648 step_action = StepNext;
2649 break_point_hit_count = 0;
2650 foo->Call(env->Global(), kArgc, args);
2651
2652 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002653 CHECK_EQ(33, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002654
2655 v8::Debug::SetDebugEventListener(NULL);
2656 CheckDebuggerUnloaded();
2657}
2658
2659
2660// Test of the stepping mechanism for keyed store in a loop.
2661TEST(DebugStepKeyedStoreLoop) {
2662 v8::HandleScope scope;
2663 DebugLocalContext env;
2664
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002665 // Register a debug event listener which steps and counts.
2666 v8::Debug::SetDebugEventListener(DebugEventStep);
2667
Steve Blocka7e24c12009-10-30 11:49:00 +00002668 // Create a function for testing stepping of keyed store. The statement 'y=1'
2669 // is there to have more than one breakable statement in the loop, TODO(315).
2670 v8::Local<v8::Function> foo = CompileFunction(
2671 &env,
2672 "function foo(a) {\n"
2673 " var len = a.length;\n"
2674 " for (var i = 0; i < len; i++) {\n"
2675 " y = 1;\n"
2676 " a[i] = 42;\n"
2677 " }\n"
2678 "}\n",
2679 "foo");
2680
2681 // Create array [0,1,2,3,4,5,6,7,8,9]
2682 v8::Local<v8::Array> a = v8::Array::New(10);
2683 for (int i = 0; i < 10; i++) {
2684 a->Set(v8::Number::New(i), v8::Number::New(i));
2685 }
2686
2687 // Call function without any break points to ensure inlining is in place.
2688 const int kArgc = 1;
2689 v8::Handle<v8::Value> args[kArgc] = { a };
2690 foo->Call(env->Global(), kArgc, args);
2691
Steve Blocka7e24c12009-10-30 11:49:00 +00002692 // Setup break point and step through the function.
2693 SetBreakPoint(foo, 3);
2694 step_action = StepNext;
2695 break_point_hit_count = 0;
2696 foo->Call(env->Global(), kArgc, args);
2697
2698 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002699 CHECK_EQ(32, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002700
2701 v8::Debug::SetDebugEventListener(NULL);
2702 CheckDebuggerUnloaded();
2703}
2704
2705
Kristian Monsen25f61362010-05-21 11:50:48 +01002706// Test of the stepping mechanism for named load in a loop.
2707TEST(DebugStepNamedLoadLoop) {
2708 v8::HandleScope scope;
2709 DebugLocalContext env;
2710
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002711 // Register a debug event listener which steps and counts.
2712 v8::Debug::SetDebugEventListener(DebugEventStep);
2713
Kristian Monsen25f61362010-05-21 11:50:48 +01002714 // Create a function for testing stepping of named load.
2715 v8::Local<v8::Function> foo = CompileFunction(
2716 &env,
2717 "function foo() {\n"
2718 " var a = [];\n"
2719 " var s = \"\";\n"
2720 " for (var i = 0; i < 10; i++) {\n"
2721 " var v = new V(i, i + 1);\n"
2722 " v.y;\n"
2723 " a.length;\n" // Special case: array length.
2724 " s.length;\n" // Special case: string length.
2725 " }\n"
2726 "}\n"
2727 "function V(x, y) {\n"
2728 " this.x = x;\n"
2729 " this.y = y;\n"
2730 "}\n",
2731 "foo");
2732
2733 // Call function without any break points to ensure inlining is in place.
2734 foo->Call(env->Global(), 0, NULL);
2735
Kristian Monsen25f61362010-05-21 11:50:48 +01002736 // Setup break point and step through the function.
2737 SetBreakPoint(foo, 4);
2738 step_action = StepNext;
2739 break_point_hit_count = 0;
2740 foo->Call(env->Global(), 0, NULL);
2741
2742 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002743 CHECK_EQ(53, break_point_hit_count);
Kristian Monsen25f61362010-05-21 11:50:48 +01002744
2745 v8::Debug::SetDebugEventListener(NULL);
2746 CheckDebuggerUnloaded();
2747}
2748
2749
Iain Merrick75681382010-08-19 15:07:18 +01002750static void DoDebugStepNamedStoreLoop(int expected, bool full_compiler = true) {
2751 v8::HandleScope scope;
2752 DebugLocalContext env;
2753
2754 // Register a debug event listener which steps and counts before compiling the
2755 // function to ensure the full compiler is used.
2756 if (full_compiler) {
2757 v8::Debug::SetDebugEventListener(DebugEventStep);
2758 }
2759
2760 // Create a function for testing stepping of named store.
2761 v8::Local<v8::Function> foo = CompileFunction(
2762 &env,
2763 "function foo() {\n"
2764 " var a = {a:1};\n"
2765 " for (var i = 0; i < 10; i++) {\n"
2766 " a.a = 2\n"
2767 " }\n"
2768 "}\n",
2769 "foo");
2770
2771 // Call function without any break points to ensure inlining is in place.
2772 foo->Call(env->Global(), 0, NULL);
2773
2774 // Register a debug event listener which steps and counts after compiling the
2775 // function to ensure the optimizing compiler is used.
2776 if (!full_compiler) {
2777 v8::Debug::SetDebugEventListener(DebugEventStep);
2778 }
2779
2780 // Setup break point and step through the function.
2781 SetBreakPoint(foo, 3);
2782 step_action = StepNext;
2783 break_point_hit_count = 0;
2784 foo->Call(env->Global(), 0, NULL);
2785
2786 // With stepping all expected break locations are hit.
2787 CHECK_EQ(expected, break_point_hit_count);
2788
2789 v8::Debug::SetDebugEventListener(NULL);
2790 CheckDebuggerUnloaded();
2791}
2792
2793
2794// Test of the stepping mechanism for named load in a loop.
2795TEST(DebugStepNamedStoreLoopFull) {
2796 // With the full compiler it is possible to break on the for statement.
2797 DoDebugStepNamedStoreLoop(22);
2798}
2799
2800
2801// Test of the stepping mechanism for named load in a loop.
2802TEST(DebugStepNamedStoreLoopOptimizing) {
2803 // With the optimizing compiler it is not possible to break on the for
2804 // statement as it uses a local variable thus no IC's.
2805 DoDebugStepNamedStoreLoop(11, false);
2806}
2807
2808
Steve Blocka7e24c12009-10-30 11:49:00 +00002809// Test the stepping mechanism with different ICs.
2810TEST(DebugStepLinearMixedICs) {
2811 v8::HandleScope scope;
2812 DebugLocalContext env;
2813
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002814 // Register a debug event listener which steps and counts.
2815 v8::Debug::SetDebugEventListener(DebugEventStep);
2816
Steve Blocka7e24c12009-10-30 11:49:00 +00002817 // Create a function for testing stepping.
2818 v8::Local<v8::Function> foo = CompileFunction(&env,
2819 "function bar() {};"
2820 "function foo() {"
2821 " var x;"
2822 " var index='name';"
2823 " var y = {};"
2824 " a=1;b=2;x=a;y[index]=3;x=y[index];bar();}", "foo");
2825 SetBreakPoint(foo, 0);
2826
Steve Blocka7e24c12009-10-30 11:49:00 +00002827 step_action = StepIn;
2828 break_point_hit_count = 0;
2829 foo->Call(env->Global(), 0, NULL);
2830
2831 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002832 CHECK_EQ(11, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002833
2834 v8::Debug::SetDebugEventListener(NULL);
2835 CheckDebuggerUnloaded();
2836
2837 // Register a debug event listener which just counts.
2838 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2839
2840 SetBreakPoint(foo, 0);
2841 break_point_hit_count = 0;
2842 foo->Call(env->Global(), 0, NULL);
2843
2844 // Without stepping only active break points are hit.
2845 CHECK_EQ(1, break_point_hit_count);
2846
2847 v8::Debug::SetDebugEventListener(NULL);
2848 CheckDebuggerUnloaded();
2849}
2850
2851
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002852TEST(DebugStepDeclarations) {
2853 v8::HandleScope scope;
2854 DebugLocalContext env;
2855
2856 // Register a debug event listener which steps and counts.
2857 v8::Debug::SetDebugEventListener(DebugEventStep);
2858
2859 // Create a function for testing stepping.
2860 const char* src = "function foo() { "
2861 " var a;"
2862 " var b = 1;"
2863 " var c = foo;"
2864 " var d = Math.floor;"
2865 " var e = b + d(1.2);"
2866 "}";
2867 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2868 SetBreakPoint(foo, 0);
2869
2870 // Stepping through the declarations.
2871 step_action = StepIn;
2872 break_point_hit_count = 0;
2873 foo->Call(env->Global(), 0, NULL);
2874 CHECK_EQ(6, break_point_hit_count);
2875
2876 // Get rid of the debug event listener.
2877 v8::Debug::SetDebugEventListener(NULL);
2878 CheckDebuggerUnloaded();
2879}
2880
2881
2882TEST(DebugStepLocals) {
2883 v8::HandleScope scope;
2884 DebugLocalContext env;
2885
2886 // Register a debug event listener which steps and counts.
2887 v8::Debug::SetDebugEventListener(DebugEventStep);
2888
2889 // Create a function for testing stepping.
2890 const char* src = "function foo() { "
2891 " var a,b;"
2892 " a = 1;"
2893 " b = a + 2;"
2894 " b = 1 + 2 + 3;"
2895 " a = Math.floor(b);"
2896 "}";
2897 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2898 SetBreakPoint(foo, 0);
2899
2900 // Stepping through the declarations.
2901 step_action = StepIn;
2902 break_point_hit_count = 0;
2903 foo->Call(env->Global(), 0, NULL);
2904 CHECK_EQ(6, break_point_hit_count);
2905
2906 // Get rid of the debug event listener.
2907 v8::Debug::SetDebugEventListener(NULL);
2908 CheckDebuggerUnloaded();
2909}
2910
2911
Steve Blocka7e24c12009-10-30 11:49:00 +00002912TEST(DebugStepIf) {
2913 v8::HandleScope scope;
2914 DebugLocalContext env;
2915
2916 // Register a debug event listener which steps and counts.
2917 v8::Debug::SetDebugEventListener(DebugEventStep);
2918
2919 // Create a function for testing stepping.
2920 const int argc = 1;
2921 const char* src = "function foo(x) { "
2922 " a = 1;"
2923 " if (x) {"
2924 " b = 1;"
2925 " } else {"
2926 " c = 1;"
2927 " d = 1;"
2928 " }"
2929 "}";
2930 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2931 SetBreakPoint(foo, 0);
2932
2933 // Stepping through the true part.
2934 step_action = StepIn;
2935 break_point_hit_count = 0;
2936 v8::Handle<v8::Value> argv_true[argc] = { v8::True() };
2937 foo->Call(env->Global(), argc, argv_true);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002938 CHECK_EQ(4, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002939
2940 // Stepping through the false part.
2941 step_action = StepIn;
2942 break_point_hit_count = 0;
2943 v8::Handle<v8::Value> argv_false[argc] = { v8::False() };
2944 foo->Call(env->Global(), argc, argv_false);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002945 CHECK_EQ(5, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002946
2947 // Get rid of the debug event listener.
2948 v8::Debug::SetDebugEventListener(NULL);
2949 CheckDebuggerUnloaded();
2950}
2951
2952
2953TEST(DebugStepSwitch) {
2954 v8::HandleScope scope;
2955 DebugLocalContext env;
2956
2957 // Register a debug event listener which steps and counts.
2958 v8::Debug::SetDebugEventListener(DebugEventStep);
2959
2960 // Create a function for testing stepping.
2961 const int argc = 1;
2962 const char* src = "function foo(x) { "
2963 " a = 1;"
2964 " switch (x) {"
2965 " case 1:"
2966 " b = 1;"
2967 " case 2:"
2968 " c = 1;"
2969 " break;"
2970 " case 3:"
2971 " d = 1;"
2972 " e = 1;"
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002973 " f = 1;"
Steve Blocka7e24c12009-10-30 11:49:00 +00002974 " break;"
2975 " }"
2976 "}";
2977 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2978 SetBreakPoint(foo, 0);
2979
2980 // One case with fall-through.
2981 step_action = StepIn;
2982 break_point_hit_count = 0;
2983 v8::Handle<v8::Value> argv_1[argc] = { v8::Number::New(1) };
2984 foo->Call(env->Global(), argc, argv_1);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002985 CHECK_EQ(6, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002986
2987 // Another case.
2988 step_action = StepIn;
2989 break_point_hit_count = 0;
2990 v8::Handle<v8::Value> argv_2[argc] = { v8::Number::New(2) };
2991 foo->Call(env->Global(), argc, argv_2);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002992 CHECK_EQ(5, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002993
2994 // Last case.
2995 step_action = StepIn;
2996 break_point_hit_count = 0;
2997 v8::Handle<v8::Value> argv_3[argc] = { v8::Number::New(3) };
2998 foo->Call(env->Global(), argc, argv_3);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002999 CHECK_EQ(7, break_point_hit_count);
3000
3001 // Get rid of the debug event listener.
3002 v8::Debug::SetDebugEventListener(NULL);
3003 CheckDebuggerUnloaded();
3004}
3005
3006
3007TEST(DebugStepWhile) {
3008 v8::HandleScope scope;
3009 DebugLocalContext env;
3010
3011 // Register a debug event listener which steps and counts.
3012 v8::Debug::SetDebugEventListener(DebugEventStep);
3013
3014 // Create a function for testing stepping.
3015 const int argc = 1;
3016 const char* src = "function foo(x) { "
3017 " var a = 0;"
3018 " while (a < x) {"
3019 " a++;"
3020 " }"
3021 "}";
3022 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3023 SetBreakPoint(foo, 8); // "var a = 0;"
3024
3025 // Looping 10 times.
3026 step_action = StepIn;
3027 break_point_hit_count = 0;
3028 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3029 foo->Call(env->Global(), argc, argv_10);
3030 CHECK_EQ(23, break_point_hit_count);
3031
3032 // Looping 100 times.
3033 step_action = StepIn;
3034 break_point_hit_count = 0;
3035 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3036 foo->Call(env->Global(), argc, argv_100);
3037 CHECK_EQ(203, break_point_hit_count);
3038
3039 // Get rid of the debug event listener.
3040 v8::Debug::SetDebugEventListener(NULL);
3041 CheckDebuggerUnloaded();
3042}
3043
3044
3045TEST(DebugStepDoWhile) {
3046 v8::HandleScope scope;
3047 DebugLocalContext env;
3048
3049 // Register a debug event listener which steps and counts.
3050 v8::Debug::SetDebugEventListener(DebugEventStep);
3051
3052 // Create a function for testing stepping.
3053 const int argc = 1;
3054 const char* src = "function foo(x) { "
3055 " var a = 0;"
3056 " do {"
3057 " a++;"
3058 " } while (a < x)"
3059 "}";
3060 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3061 SetBreakPoint(foo, 8); // "var a = 0;"
3062
3063 // Looping 10 times.
3064 step_action = StepIn;
3065 break_point_hit_count = 0;
3066 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3067 foo->Call(env->Global(), argc, argv_10);
3068 CHECK_EQ(22, break_point_hit_count);
3069
3070 // Looping 100 times.
3071 step_action = StepIn;
3072 break_point_hit_count = 0;
3073 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3074 foo->Call(env->Global(), argc, argv_100);
3075 CHECK_EQ(202, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003076
3077 // Get rid of the debug event listener.
3078 v8::Debug::SetDebugEventListener(NULL);
3079 CheckDebuggerUnloaded();
3080}
3081
3082
3083TEST(DebugStepFor) {
3084 v8::HandleScope scope;
3085 DebugLocalContext env;
3086
3087 // Register a debug event listener which steps and counts.
3088 v8::Debug::SetDebugEventListener(DebugEventStep);
3089
3090 // Create a function for testing stepping.
3091 const int argc = 1;
3092 const char* src = "function foo(x) { "
3093 " a = 1;"
3094 " for (i = 0; i < x; i++) {"
3095 " b = 1;"
3096 " }"
3097 "}";
3098 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3099 SetBreakPoint(foo, 8); // "a = 1;"
3100
3101 // Looping 10 times.
3102 step_action = StepIn;
3103 break_point_hit_count = 0;
3104 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3105 foo->Call(env->Global(), argc, argv_10);
3106 CHECK_EQ(23, break_point_hit_count);
3107
3108 // Looping 100 times.
3109 step_action = StepIn;
3110 break_point_hit_count = 0;
3111 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3112 foo->Call(env->Global(), argc, argv_100);
3113 CHECK_EQ(203, break_point_hit_count);
3114
3115 // Get rid of the debug event listener.
3116 v8::Debug::SetDebugEventListener(NULL);
3117 CheckDebuggerUnloaded();
3118}
3119
3120
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003121TEST(DebugStepForContinue) {
3122 v8::HandleScope scope;
3123 DebugLocalContext env;
3124
3125 // Register a debug event listener which steps and counts.
3126 v8::Debug::SetDebugEventListener(DebugEventStep);
3127
3128 // Create a function for testing stepping.
3129 const int argc = 1;
3130 const char* src = "function foo(x) { "
3131 " var a = 0;"
3132 " var b = 0;"
3133 " var c = 0;"
3134 " for (var i = 0; i < x; i++) {"
3135 " a++;"
3136 " if (a % 2 == 0) continue;"
3137 " b++;"
3138 " c++;"
3139 " }"
3140 " return b;"
3141 "}";
3142 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3143 v8::Handle<v8::Value> result;
3144 SetBreakPoint(foo, 8); // "var a = 0;"
3145
3146 // Each loop generates 4 or 5 steps depending on whether a is equal.
3147
3148 // Looping 10 times.
3149 step_action = StepIn;
3150 break_point_hit_count = 0;
3151 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3152 result = foo->Call(env->Global(), argc, argv_10);
3153 CHECK_EQ(5, result->Int32Value());
3154 CHECK_EQ(50, break_point_hit_count);
3155
3156 // Looping 100 times.
3157 step_action = StepIn;
3158 break_point_hit_count = 0;
3159 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3160 result = foo->Call(env->Global(), argc, argv_100);
3161 CHECK_EQ(50, result->Int32Value());
3162 CHECK_EQ(455, break_point_hit_count);
3163
3164 // Get rid of the debug event listener.
3165 v8::Debug::SetDebugEventListener(NULL);
3166 CheckDebuggerUnloaded();
3167}
3168
3169
3170TEST(DebugStepForBreak) {
3171 v8::HandleScope scope;
3172 DebugLocalContext env;
3173
3174 // Register a debug event listener which steps and counts.
3175 v8::Debug::SetDebugEventListener(DebugEventStep);
3176
3177 // Create a function for testing stepping.
3178 const int argc = 1;
3179 const char* src = "function foo(x) { "
3180 " var a = 0;"
3181 " var b = 0;"
3182 " var c = 0;"
3183 " for (var i = 0; i < 1000; i++) {"
3184 " a++;"
3185 " if (a == x) break;"
3186 " b++;"
3187 " c++;"
3188 " }"
3189 " return b;"
3190 "}";
3191 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3192 v8::Handle<v8::Value> result;
3193 SetBreakPoint(foo, 8); // "var a = 0;"
3194
3195 // Each loop generates 5 steps except for the last (when break is executed)
3196 // which only generates 4.
3197
3198 // Looping 10 times.
3199 step_action = StepIn;
3200 break_point_hit_count = 0;
3201 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3202 result = foo->Call(env->Global(), argc, argv_10);
3203 CHECK_EQ(9, result->Int32Value());
3204 CHECK_EQ(53, break_point_hit_count);
3205
3206 // Looping 100 times.
3207 step_action = StepIn;
3208 break_point_hit_count = 0;
3209 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3210 result = foo->Call(env->Global(), argc, argv_100);
3211 CHECK_EQ(99, result->Int32Value());
3212 CHECK_EQ(503, break_point_hit_count);
3213
3214 // Get rid of the debug event listener.
3215 v8::Debug::SetDebugEventListener(NULL);
3216 CheckDebuggerUnloaded();
3217}
3218
3219
3220TEST(DebugStepForIn) {
3221 v8::HandleScope scope;
3222 DebugLocalContext env;
3223
3224 // Register a debug event listener which steps and counts.
3225 v8::Debug::SetDebugEventListener(DebugEventStep);
3226
3227 v8::Local<v8::Function> foo;
3228 const char* src_1 = "function foo() { "
3229 " var a = [1, 2];"
3230 " for (x in a) {"
3231 " b = 0;"
3232 " }"
3233 "}";
3234 foo = CompileFunction(&env, src_1, "foo");
3235 SetBreakPoint(foo, 0); // "var a = ..."
3236
3237 step_action = StepIn;
3238 break_point_hit_count = 0;
3239 foo->Call(env->Global(), 0, NULL);
3240 CHECK_EQ(6, break_point_hit_count);
3241
3242 const char* src_2 = "function foo() { "
3243 " var a = {a:[1, 2, 3]};"
3244 " for (x in a.a) {"
3245 " b = 0;"
3246 " }"
3247 "}";
3248 foo = CompileFunction(&env, src_2, "foo");
3249 SetBreakPoint(foo, 0); // "var a = ..."
3250
3251 step_action = StepIn;
3252 break_point_hit_count = 0;
3253 foo->Call(env->Global(), 0, NULL);
3254 CHECK_EQ(8, break_point_hit_count);
3255
3256 // Get rid of the debug event listener.
3257 v8::Debug::SetDebugEventListener(NULL);
3258 CheckDebuggerUnloaded();
3259}
3260
3261
3262TEST(DebugStepWith) {
3263 v8::HandleScope scope;
3264 DebugLocalContext env;
3265
3266 // Register a debug event listener which steps and counts.
3267 v8::Debug::SetDebugEventListener(DebugEventStep);
3268
3269 // Create a function for testing stepping.
3270 const char* src = "function foo(x) { "
3271 " var a = {};"
3272 " with (a) {}"
3273 " with (b) {}"
3274 "}";
3275 env->Global()->Set(v8::String::New("b"), v8::Object::New());
3276 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3277 v8::Handle<v8::Value> result;
3278 SetBreakPoint(foo, 8); // "var a = {};"
3279
3280 step_action = StepIn;
3281 break_point_hit_count = 0;
3282 foo->Call(env->Global(), 0, NULL);
3283 CHECK_EQ(4, break_point_hit_count);
3284
3285 // Get rid of the debug event listener.
3286 v8::Debug::SetDebugEventListener(NULL);
3287 CheckDebuggerUnloaded();
3288}
3289
3290
3291TEST(DebugConditional) {
3292 v8::HandleScope scope;
3293 DebugLocalContext env;
3294
3295 // Register a debug event listener which steps and counts.
3296 v8::Debug::SetDebugEventListener(DebugEventStep);
3297
3298 // Create a function for testing stepping.
3299 const char* src = "function foo(x) { "
3300 " var a;"
3301 " a = x ? 1 : 2;"
3302 " return a;"
3303 "}";
3304 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3305 SetBreakPoint(foo, 0); // "var a;"
3306
3307 step_action = StepIn;
3308 break_point_hit_count = 0;
3309 foo->Call(env->Global(), 0, NULL);
3310 CHECK_EQ(5, break_point_hit_count);
3311
3312 step_action = StepIn;
3313 break_point_hit_count = 0;
3314 const int argc = 1;
3315 v8::Handle<v8::Value> argv_true[argc] = { v8::True() };
3316 foo->Call(env->Global(), argc, argv_true);
3317 CHECK_EQ(5, break_point_hit_count);
3318
3319 // Get rid of the debug event listener.
3320 v8::Debug::SetDebugEventListener(NULL);
3321 CheckDebuggerUnloaded();
3322}
3323
3324
Steve Blocka7e24c12009-10-30 11:49:00 +00003325TEST(StepInOutSimple) {
3326 v8::HandleScope scope;
3327 DebugLocalContext env;
3328
3329 // Create a function for checking the function when hitting a break point.
3330 frame_function_name = CompileFunction(&env,
3331 frame_function_name_source,
3332 "frame_function_name");
3333
3334 // Register a debug event listener which steps and counts.
3335 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3336
3337 // Create functions for testing stepping.
3338 const char* src = "function a() {b();c();}; "
3339 "function b() {c();}; "
3340 "function c() {}; ";
3341 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3342 SetBreakPoint(a, 0);
3343
3344 // Step through invocation of a with step in.
3345 step_action = StepIn;
3346 break_point_hit_count = 0;
3347 expected_step_sequence = "abcbaca";
3348 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003349 CHECK_EQ(StrLength(expected_step_sequence),
3350 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003351
3352 // Step through invocation of a with step next.
3353 step_action = StepNext;
3354 break_point_hit_count = 0;
3355 expected_step_sequence = "aaa";
3356 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003357 CHECK_EQ(StrLength(expected_step_sequence),
3358 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003359
3360 // Step through invocation of a with step out.
3361 step_action = StepOut;
3362 break_point_hit_count = 0;
3363 expected_step_sequence = "a";
3364 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003365 CHECK_EQ(StrLength(expected_step_sequence),
3366 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003367
3368 // Get rid of the debug event listener.
3369 v8::Debug::SetDebugEventListener(NULL);
3370 CheckDebuggerUnloaded();
3371}
3372
3373
3374TEST(StepInOutTree) {
3375 v8::HandleScope scope;
3376 DebugLocalContext env;
3377
3378 // Create a function for checking the function when hitting a break point.
3379 frame_function_name = CompileFunction(&env,
3380 frame_function_name_source,
3381 "frame_function_name");
3382
3383 // Register a debug event listener which steps and counts.
3384 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3385
3386 // Create functions for testing stepping.
3387 const char* src = "function a() {b(c(d()),d());c(d());d()}; "
3388 "function b(x,y) {c();}; "
3389 "function c(x) {}; "
3390 "function d() {}; ";
3391 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3392 SetBreakPoint(a, 0);
3393
3394 // Step through invocation of a with step in.
3395 step_action = StepIn;
3396 break_point_hit_count = 0;
3397 expected_step_sequence = "adacadabcbadacada";
3398 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003399 CHECK_EQ(StrLength(expected_step_sequence),
3400 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003401
3402 // Step through invocation of a with step next.
3403 step_action = StepNext;
3404 break_point_hit_count = 0;
3405 expected_step_sequence = "aaaa";
3406 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003407 CHECK_EQ(StrLength(expected_step_sequence),
3408 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003409
3410 // Step through invocation of a with step out.
3411 step_action = StepOut;
3412 break_point_hit_count = 0;
3413 expected_step_sequence = "a";
3414 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003415 CHECK_EQ(StrLength(expected_step_sequence),
3416 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003417
3418 // Get rid of the debug event listener.
3419 v8::Debug::SetDebugEventListener(NULL);
3420 CheckDebuggerUnloaded(true);
3421}
3422
3423
3424TEST(StepInOutBranch) {
3425 v8::HandleScope scope;
3426 DebugLocalContext env;
3427
3428 // Create a function for checking the function when hitting a break point.
3429 frame_function_name = CompileFunction(&env,
3430 frame_function_name_source,
3431 "frame_function_name");
3432
3433 // Register a debug event listener which steps and counts.
3434 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3435
3436 // Create functions for testing stepping.
3437 const char* src = "function a() {b(false);c();}; "
3438 "function b(x) {if(x){c();};}; "
3439 "function c() {}; ";
3440 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3441 SetBreakPoint(a, 0);
3442
3443 // Step through invocation of a.
3444 step_action = StepIn;
3445 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003446 expected_step_sequence = "abbaca";
Steve Blocka7e24c12009-10-30 11:49:00 +00003447 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003448 CHECK_EQ(StrLength(expected_step_sequence),
3449 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003450
3451 // Get rid of the debug event listener.
3452 v8::Debug::SetDebugEventListener(NULL);
3453 CheckDebuggerUnloaded();
3454}
3455
3456
3457// Test that step in does not step into native functions.
3458TEST(DebugStepNatives) {
3459 v8::HandleScope scope;
3460 DebugLocalContext env;
3461
3462 // Create a function for testing stepping.
3463 v8::Local<v8::Function> foo = CompileFunction(
3464 &env,
3465 "function foo(){debugger;Math.sin(1);}",
3466 "foo");
3467
3468 // Register a debug event listener which steps and counts.
3469 v8::Debug::SetDebugEventListener(DebugEventStep);
3470
3471 step_action = StepIn;
3472 break_point_hit_count = 0;
3473 foo->Call(env->Global(), 0, NULL);
3474
3475 // With stepping all break locations are hit.
3476 CHECK_EQ(3, break_point_hit_count);
3477
3478 v8::Debug::SetDebugEventListener(NULL);
3479 CheckDebuggerUnloaded();
3480
3481 // Register a debug event listener which just counts.
3482 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3483
3484 break_point_hit_count = 0;
3485 foo->Call(env->Global(), 0, NULL);
3486
3487 // Without stepping only active break points are hit.
3488 CHECK_EQ(1, break_point_hit_count);
3489
3490 v8::Debug::SetDebugEventListener(NULL);
3491 CheckDebuggerUnloaded();
3492}
3493
3494
3495// Test that step in works with function.apply.
3496TEST(DebugStepFunctionApply) {
3497 v8::HandleScope scope;
3498 DebugLocalContext env;
3499
3500 // Create a function for testing stepping.
3501 v8::Local<v8::Function> foo = CompileFunction(
3502 &env,
3503 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3504 "function foo(){ debugger; bar.apply(this, [1,2,3]); }",
3505 "foo");
3506
3507 // Register a debug event listener which steps and counts.
3508 v8::Debug::SetDebugEventListener(DebugEventStep);
3509
3510 step_action = StepIn;
3511 break_point_hit_count = 0;
3512 foo->Call(env->Global(), 0, NULL);
3513
3514 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003515 CHECK_EQ(7, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003516
3517 v8::Debug::SetDebugEventListener(NULL);
3518 CheckDebuggerUnloaded();
3519
3520 // Register a debug event listener which just counts.
3521 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3522
3523 break_point_hit_count = 0;
3524 foo->Call(env->Global(), 0, NULL);
3525
3526 // Without stepping only the debugger statement is hit.
3527 CHECK_EQ(1, break_point_hit_count);
3528
3529 v8::Debug::SetDebugEventListener(NULL);
3530 CheckDebuggerUnloaded();
3531}
3532
3533
3534// Test that step in works with function.call.
3535TEST(DebugStepFunctionCall) {
3536 v8::HandleScope scope;
3537 DebugLocalContext env;
3538
3539 // Create a function for testing stepping.
3540 v8::Local<v8::Function> foo = CompileFunction(
3541 &env,
3542 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3543 "function foo(a){ debugger;"
3544 " if (a) {"
3545 " bar.call(this, 1, 2, 3);"
3546 " } else {"
3547 " bar.call(this, 0);"
3548 " }"
3549 "}",
3550 "foo");
3551
3552 // Register a debug event listener which steps and counts.
3553 v8::Debug::SetDebugEventListener(DebugEventStep);
3554 step_action = StepIn;
3555
3556 // Check stepping where the if condition in bar is false.
3557 break_point_hit_count = 0;
3558 foo->Call(env->Global(), 0, NULL);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003559 CHECK_EQ(6, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003560
3561 // Check stepping where the if condition in bar is true.
3562 break_point_hit_count = 0;
3563 const int argc = 1;
3564 v8::Handle<v8::Value> argv[argc] = { v8::True() };
3565 foo->Call(env->Global(), argc, argv);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003566 CHECK_EQ(8, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003567
3568 v8::Debug::SetDebugEventListener(NULL);
3569 CheckDebuggerUnloaded();
3570
3571 // Register a debug event listener which just counts.
3572 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3573
3574 break_point_hit_count = 0;
3575 foo->Call(env->Global(), 0, NULL);
3576
3577 // Without stepping only the debugger statement is hit.
3578 CHECK_EQ(1, break_point_hit_count);
3579
3580 v8::Debug::SetDebugEventListener(NULL);
3581 CheckDebuggerUnloaded();
3582}
3583
3584
Steve Blockd0582a62009-12-15 09:54:21 +00003585// Tests that breakpoint will be hit if it's set in script.
3586TEST(PauseInScript) {
3587 v8::HandleScope scope;
3588 DebugLocalContext env;
3589 env.ExposeDebug();
3590
3591 // Register a debug event listener which counts.
3592 v8::Debug::SetDebugEventListener(DebugEventCounter);
3593
3594 // Create a script that returns a function.
3595 const char* src = "(function (evt) {})";
3596 const char* script_name = "StepInHandlerTest";
3597
3598 // Set breakpoint in the script.
3599 SetScriptBreakPointByNameFromJS(script_name, 0, -1);
3600 break_point_hit_count = 0;
3601
3602 v8::ScriptOrigin origin(v8::String::New(script_name), v8::Integer::New(0));
3603 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(src),
3604 &origin);
3605 v8::Local<v8::Value> r = script->Run();
3606
3607 CHECK(r->IsFunction());
3608 CHECK_EQ(1, break_point_hit_count);
3609
3610 // Get rid of the debug event listener.
3611 v8::Debug::SetDebugEventListener(NULL);
3612 CheckDebuggerUnloaded();
3613}
3614
3615
Steve Blocka7e24c12009-10-30 11:49:00 +00003616// Test break on exceptions. For each exception break combination the number
3617// of debug event exception callbacks and message callbacks are collected. The
3618// number of debug event exception callbacks are used to check that the
3619// debugger is called correctly and the number of message callbacks is used to
3620// check that uncaught exceptions are still returned even if there is a break
3621// for them.
3622TEST(BreakOnException) {
3623 v8::HandleScope scope;
3624 DebugLocalContext env;
3625 env.ExposeDebug();
3626
3627 v8::internal::Top::TraceException(false);
3628
3629 // Create functions for testing break on exception.
3630 v8::Local<v8::Function> throws =
3631 CompileFunction(&env, "function throws(){throw 1;}", "throws");
3632 v8::Local<v8::Function> caught =
3633 CompileFunction(&env,
3634 "function caught(){try {throws();} catch(e) {};}",
3635 "caught");
3636 v8::Local<v8::Function> notCaught =
3637 CompileFunction(&env, "function notCaught(){throws();}", "notCaught");
3638
3639 v8::V8::AddMessageListener(MessageCallbackCount);
3640 v8::Debug::SetDebugEventListener(DebugEventCounter);
3641
3642 // Initial state should be break on uncaught exception.
3643 DebugEventCounterClear();
3644 MessageCallbackCountClear();
3645 caught->Call(env->Global(), 0, NULL);
3646 CHECK_EQ(0, exception_hit_count);
3647 CHECK_EQ(0, uncaught_exception_hit_count);
3648 CHECK_EQ(0, message_callback_count);
3649 notCaught->Call(env->Global(), 0, NULL);
3650 CHECK_EQ(1, exception_hit_count);
3651 CHECK_EQ(1, uncaught_exception_hit_count);
3652 CHECK_EQ(1, message_callback_count);
3653
3654 // No break on exception
3655 DebugEventCounterClear();
3656 MessageCallbackCountClear();
3657 ChangeBreakOnException(false, false);
3658 caught->Call(env->Global(), 0, NULL);
3659 CHECK_EQ(0, exception_hit_count);
3660 CHECK_EQ(0, uncaught_exception_hit_count);
3661 CHECK_EQ(0, message_callback_count);
3662 notCaught->Call(env->Global(), 0, NULL);
3663 CHECK_EQ(0, exception_hit_count);
3664 CHECK_EQ(0, uncaught_exception_hit_count);
3665 CHECK_EQ(1, message_callback_count);
3666
3667 // Break on uncaught exception
3668 DebugEventCounterClear();
3669 MessageCallbackCountClear();
3670 ChangeBreakOnException(false, true);
3671 caught->Call(env->Global(), 0, NULL);
3672 CHECK_EQ(0, exception_hit_count);
3673 CHECK_EQ(0, uncaught_exception_hit_count);
3674 CHECK_EQ(0, message_callback_count);
3675 notCaught->Call(env->Global(), 0, NULL);
3676 CHECK_EQ(1, exception_hit_count);
3677 CHECK_EQ(1, uncaught_exception_hit_count);
3678 CHECK_EQ(1, message_callback_count);
3679
3680 // Break on exception and uncaught exception
3681 DebugEventCounterClear();
3682 MessageCallbackCountClear();
3683 ChangeBreakOnException(true, true);
3684 caught->Call(env->Global(), 0, NULL);
3685 CHECK_EQ(1, exception_hit_count);
3686 CHECK_EQ(0, uncaught_exception_hit_count);
3687 CHECK_EQ(0, message_callback_count);
3688 notCaught->Call(env->Global(), 0, NULL);
3689 CHECK_EQ(2, exception_hit_count);
3690 CHECK_EQ(1, uncaught_exception_hit_count);
3691 CHECK_EQ(1, message_callback_count);
3692
3693 // Break on exception
3694 DebugEventCounterClear();
3695 MessageCallbackCountClear();
3696 ChangeBreakOnException(true, false);
3697 caught->Call(env->Global(), 0, NULL);
3698 CHECK_EQ(1, exception_hit_count);
3699 CHECK_EQ(0, uncaught_exception_hit_count);
3700 CHECK_EQ(0, message_callback_count);
3701 notCaught->Call(env->Global(), 0, NULL);
3702 CHECK_EQ(2, exception_hit_count);
3703 CHECK_EQ(1, uncaught_exception_hit_count);
3704 CHECK_EQ(1, message_callback_count);
3705
3706 // No break on exception using JavaScript
3707 DebugEventCounterClear();
3708 MessageCallbackCountClear();
3709 ChangeBreakOnExceptionFromJS(false, false);
3710 caught->Call(env->Global(), 0, NULL);
3711 CHECK_EQ(0, exception_hit_count);
3712 CHECK_EQ(0, uncaught_exception_hit_count);
3713 CHECK_EQ(0, message_callback_count);
3714 notCaught->Call(env->Global(), 0, NULL);
3715 CHECK_EQ(0, exception_hit_count);
3716 CHECK_EQ(0, uncaught_exception_hit_count);
3717 CHECK_EQ(1, message_callback_count);
3718
3719 // Break on uncaught exception using JavaScript
3720 DebugEventCounterClear();
3721 MessageCallbackCountClear();
3722 ChangeBreakOnExceptionFromJS(false, true);
3723 caught->Call(env->Global(), 0, NULL);
3724 CHECK_EQ(0, exception_hit_count);
3725 CHECK_EQ(0, uncaught_exception_hit_count);
3726 CHECK_EQ(0, message_callback_count);
3727 notCaught->Call(env->Global(), 0, NULL);
3728 CHECK_EQ(1, exception_hit_count);
3729 CHECK_EQ(1, uncaught_exception_hit_count);
3730 CHECK_EQ(1, message_callback_count);
3731
3732 // Break on exception and uncaught exception using JavaScript
3733 DebugEventCounterClear();
3734 MessageCallbackCountClear();
3735 ChangeBreakOnExceptionFromJS(true, true);
3736 caught->Call(env->Global(), 0, NULL);
3737 CHECK_EQ(1, exception_hit_count);
3738 CHECK_EQ(0, message_callback_count);
3739 CHECK_EQ(0, uncaught_exception_hit_count);
3740 notCaught->Call(env->Global(), 0, NULL);
3741 CHECK_EQ(2, exception_hit_count);
3742 CHECK_EQ(1, uncaught_exception_hit_count);
3743 CHECK_EQ(1, message_callback_count);
3744
3745 // Break on exception using JavaScript
3746 DebugEventCounterClear();
3747 MessageCallbackCountClear();
3748 ChangeBreakOnExceptionFromJS(true, false);
3749 caught->Call(env->Global(), 0, NULL);
3750 CHECK_EQ(1, exception_hit_count);
3751 CHECK_EQ(0, uncaught_exception_hit_count);
3752 CHECK_EQ(0, message_callback_count);
3753 notCaught->Call(env->Global(), 0, NULL);
3754 CHECK_EQ(2, exception_hit_count);
3755 CHECK_EQ(1, uncaught_exception_hit_count);
3756 CHECK_EQ(1, message_callback_count);
3757
3758 v8::Debug::SetDebugEventListener(NULL);
3759 CheckDebuggerUnloaded();
3760 v8::V8::RemoveMessageListeners(MessageCallbackCount);
3761}
3762
3763
3764// Test break on exception from compiler errors. When compiling using
3765// v8::Script::Compile there is no JavaScript stack whereas when compiling using
3766// eval there are JavaScript frames.
3767TEST(BreakOnCompileException) {
3768 v8::HandleScope scope;
3769 DebugLocalContext env;
3770
3771 v8::internal::Top::TraceException(false);
3772
3773 // Create a function for checking the function when hitting a break point.
3774 frame_count = CompileFunction(&env, frame_count_source, "frame_count");
3775
3776 v8::V8::AddMessageListener(MessageCallbackCount);
3777 v8::Debug::SetDebugEventListener(DebugEventCounter);
3778
3779 DebugEventCounterClear();
3780 MessageCallbackCountClear();
3781
3782 // Check initial state.
3783 CHECK_EQ(0, exception_hit_count);
3784 CHECK_EQ(0, uncaught_exception_hit_count);
3785 CHECK_EQ(0, message_callback_count);
3786 CHECK_EQ(-1, last_js_stack_height);
3787
3788 // Throws SyntaxError: Unexpected end of input
3789 v8::Script::Compile(v8::String::New("+++"));
3790 CHECK_EQ(1, exception_hit_count);
3791 CHECK_EQ(1, uncaught_exception_hit_count);
3792 CHECK_EQ(1, message_callback_count);
3793 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
3794
3795 // Throws SyntaxError: Unexpected identifier
3796 v8::Script::Compile(v8::String::New("x x"));
3797 CHECK_EQ(2, exception_hit_count);
3798 CHECK_EQ(2, uncaught_exception_hit_count);
3799 CHECK_EQ(2, message_callback_count);
3800 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
3801
3802 // Throws SyntaxError: Unexpected end of input
3803 v8::Script::Compile(v8::String::New("eval('+++')"))->Run();
3804 CHECK_EQ(3, exception_hit_count);
3805 CHECK_EQ(3, uncaught_exception_hit_count);
3806 CHECK_EQ(3, message_callback_count);
3807 CHECK_EQ(1, last_js_stack_height);
3808
3809 // Throws SyntaxError: Unexpected identifier
3810 v8::Script::Compile(v8::String::New("eval('x x')"))->Run();
3811 CHECK_EQ(4, exception_hit_count);
3812 CHECK_EQ(4, uncaught_exception_hit_count);
3813 CHECK_EQ(4, message_callback_count);
3814 CHECK_EQ(1, last_js_stack_height);
3815}
3816
3817
3818TEST(StepWithException) {
3819 v8::HandleScope scope;
3820 DebugLocalContext env;
3821
3822 // Create a function for checking the function when hitting a break point.
3823 frame_function_name = CompileFunction(&env,
3824 frame_function_name_source,
3825 "frame_function_name");
3826
3827 // Register a debug event listener which steps and counts.
3828 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3829
3830 // Create functions for testing stepping.
3831 const char* src = "function a() { n(); }; "
3832 "function b() { c(); }; "
3833 "function c() { n(); }; "
3834 "function d() { x = 1; try { e(); } catch(x) { x = 2; } }; "
3835 "function e() { n(); }; "
3836 "function f() { x = 1; try { g(); } catch(x) { x = 2; } }; "
3837 "function g() { h(); }; "
3838 "function h() { x = 1; throw 1; }; ";
3839
3840 // Step through invocation of a.
3841 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3842 SetBreakPoint(a, 0);
3843 step_action = StepIn;
3844 break_point_hit_count = 0;
3845 expected_step_sequence = "aa";
3846 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003847 CHECK_EQ(StrLength(expected_step_sequence),
3848 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003849
3850 // Step through invocation of b + c.
3851 v8::Local<v8::Function> b = CompileFunction(&env, src, "b");
3852 SetBreakPoint(b, 0);
3853 step_action = StepIn;
3854 break_point_hit_count = 0;
3855 expected_step_sequence = "bcc";
3856 b->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003857 CHECK_EQ(StrLength(expected_step_sequence),
3858 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003859 // Step through invocation of d + e.
3860 v8::Local<v8::Function> d = CompileFunction(&env, src, "d");
3861 SetBreakPoint(d, 0);
3862 ChangeBreakOnException(false, true);
3863 step_action = StepIn;
3864 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003865 expected_step_sequence = "ddedd";
Steve Blocka7e24c12009-10-30 11:49:00 +00003866 d->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003867 CHECK_EQ(StrLength(expected_step_sequence),
3868 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003869
3870 // Step through invocation of d + e now with break on caught exceptions.
3871 ChangeBreakOnException(true, true);
3872 step_action = StepIn;
3873 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003874 expected_step_sequence = "ddeedd";
Steve Blocka7e24c12009-10-30 11:49:00 +00003875 d->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003876 CHECK_EQ(StrLength(expected_step_sequence),
3877 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003878
3879 // Step through invocation of f + g + h.
3880 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
3881 SetBreakPoint(f, 0);
3882 ChangeBreakOnException(false, true);
3883 step_action = StepIn;
3884 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003885 expected_step_sequence = "ffghhff";
Steve Blocka7e24c12009-10-30 11:49:00 +00003886 f->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003887 CHECK_EQ(StrLength(expected_step_sequence),
3888 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003889
3890 // Step through invocation of f + g + h now with break on caught exceptions.
3891 ChangeBreakOnException(true, true);
3892 step_action = StepIn;
3893 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003894 expected_step_sequence = "ffghhhff";
Steve Blocka7e24c12009-10-30 11:49:00 +00003895 f->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003896 CHECK_EQ(StrLength(expected_step_sequence),
3897 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003898
3899 // Get rid of the debug event listener.
3900 v8::Debug::SetDebugEventListener(NULL);
3901 CheckDebuggerUnloaded();
3902}
3903
3904
3905TEST(DebugBreak) {
3906 v8::HandleScope scope;
3907 DebugLocalContext env;
3908
3909 // This test should be run with option --verify-heap. As --verify-heap is
3910 // only available in debug mode only check for it in that case.
3911#ifdef DEBUG
3912 CHECK(v8::internal::FLAG_verify_heap);
3913#endif
3914
3915 // Register a debug event listener which sets the break flag and counts.
3916 v8::Debug::SetDebugEventListener(DebugEventBreak);
3917
3918 // Create a function for testing stepping.
3919 const char* src = "function f0() {}"
3920 "function f1(x1) {}"
3921 "function f2(x1,x2) {}"
3922 "function f3(x1,x2,x3) {}";
3923 v8::Local<v8::Function> f0 = CompileFunction(&env, src, "f0");
3924 v8::Local<v8::Function> f1 = CompileFunction(&env, src, "f1");
3925 v8::Local<v8::Function> f2 = CompileFunction(&env, src, "f2");
3926 v8::Local<v8::Function> f3 = CompileFunction(&env, src, "f3");
3927
3928 // Call the function to make sure it is compiled.
3929 v8::Handle<v8::Value> argv[] = { v8::Number::New(1),
3930 v8::Number::New(1),
3931 v8::Number::New(1),
3932 v8::Number::New(1) };
3933
3934 // Call all functions to make sure that they are compiled.
3935 f0->Call(env->Global(), 0, NULL);
3936 f1->Call(env->Global(), 0, NULL);
3937 f2->Call(env->Global(), 0, NULL);
3938 f3->Call(env->Global(), 0, NULL);
3939
3940 // Set the debug break flag.
3941 v8::Debug::DebugBreak();
3942
3943 // Call all functions with different argument count.
3944 break_point_hit_count = 0;
3945 for (unsigned int i = 0; i < ARRAY_SIZE(argv); i++) {
3946 f0->Call(env->Global(), i, argv);
3947 f1->Call(env->Global(), i, argv);
3948 f2->Call(env->Global(), i, argv);
3949 f3->Call(env->Global(), i, argv);
3950 }
3951
3952 // One break for each function called.
3953 CHECK_EQ(4 * ARRAY_SIZE(argv), break_point_hit_count);
3954
3955 // Get rid of the debug event listener.
3956 v8::Debug::SetDebugEventListener(NULL);
3957 CheckDebuggerUnloaded();
3958}
3959
3960
3961// Test to ensure that JavaScript code keeps running while the debug break
3962// through the stack limit flag is set but breaks are disabled.
3963TEST(DisableBreak) {
3964 v8::HandleScope scope;
3965 DebugLocalContext env;
3966
3967 // Register a debug event listener which sets the break flag and counts.
3968 v8::Debug::SetDebugEventListener(DebugEventCounter);
3969
3970 // Create a function for testing stepping.
3971 const char* src = "function f() {g()};function g(){i=0; while(i<10){i++}}";
3972 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
3973
3974 // Set the debug break flag.
3975 v8::Debug::DebugBreak();
3976
3977 // Call all functions with different argument count.
3978 break_point_hit_count = 0;
3979 f->Call(env->Global(), 0, NULL);
3980 CHECK_EQ(1, break_point_hit_count);
3981
3982 {
3983 v8::Debug::DebugBreak();
3984 v8::internal::DisableBreak disable_break(true);
3985 f->Call(env->Global(), 0, NULL);
3986 CHECK_EQ(1, break_point_hit_count);
3987 }
3988
3989 f->Call(env->Global(), 0, NULL);
3990 CHECK_EQ(2, break_point_hit_count);
3991
3992 // Get rid of the debug event listener.
3993 v8::Debug::SetDebugEventListener(NULL);
3994 CheckDebuggerUnloaded();
3995}
3996
Leon Clarkee46be812010-01-19 14:06:41 +00003997static const char* kSimpleExtensionSource =
3998 "(function Foo() {"
3999 " return 4;"
4000 "})() ";
4001
4002// http://crbug.com/28933
4003// Test that debug break is disabled when bootstrapper is active.
4004TEST(NoBreakWhenBootstrapping) {
4005 v8::HandleScope scope;
4006
4007 // Register a debug event listener which sets the break flag and counts.
4008 v8::Debug::SetDebugEventListener(DebugEventCounter);
4009
4010 // Set the debug break flag.
4011 v8::Debug::DebugBreak();
4012 break_point_hit_count = 0;
4013 {
4014 // Create a context with an extension to make sure that some JavaScript
4015 // code is executed during bootstrapping.
4016 v8::RegisterExtension(new v8::Extension("simpletest",
4017 kSimpleExtensionSource));
4018 const char* extension_names[] = { "simpletest" };
4019 v8::ExtensionConfiguration extensions(1, extension_names);
4020 v8::Persistent<v8::Context> context = v8::Context::New(&extensions);
4021 context.Dispose();
4022 }
4023 // Check that no DebugBreak events occured during the context creation.
4024 CHECK_EQ(0, break_point_hit_count);
4025
4026 // Get rid of the debug event listener.
4027 v8::Debug::SetDebugEventListener(NULL);
4028 CheckDebuggerUnloaded();
4029}
Steve Blocka7e24c12009-10-30 11:49:00 +00004030
4031static v8::Handle<v8::Array> NamedEnum(const v8::AccessorInfo&) {
4032 v8::Handle<v8::Array> result = v8::Array::New(3);
4033 result->Set(v8::Integer::New(0), v8::String::New("a"));
4034 result->Set(v8::Integer::New(1), v8::String::New("b"));
4035 result->Set(v8::Integer::New(2), v8::String::New("c"));
4036 return result;
4037}
4038
4039
4040static v8::Handle<v8::Array> IndexedEnum(const v8::AccessorInfo&) {
4041 v8::Handle<v8::Array> result = v8::Array::New(2);
4042 result->Set(v8::Integer::New(0), v8::Number::New(1));
4043 result->Set(v8::Integer::New(1), v8::Number::New(10));
4044 return result;
4045}
4046
4047
4048static v8::Handle<v8::Value> NamedGetter(v8::Local<v8::String> name,
4049 const v8::AccessorInfo& info) {
4050 v8::String::AsciiValue n(name);
4051 if (strcmp(*n, "a") == 0) {
4052 return v8::String::New("AA");
4053 } else if (strcmp(*n, "b") == 0) {
4054 return v8::String::New("BB");
4055 } else if (strcmp(*n, "c") == 0) {
4056 return v8::String::New("CC");
4057 } else {
4058 return v8::Undefined();
4059 }
4060
4061 return name;
4062}
4063
4064
4065static v8::Handle<v8::Value> IndexedGetter(uint32_t index,
4066 const v8::AccessorInfo& info) {
4067 return v8::Number::New(index + 1);
4068}
4069
4070
4071TEST(InterceptorPropertyMirror) {
4072 // Create a V8 environment with debug access.
4073 v8::HandleScope scope;
4074 DebugLocalContext env;
4075 env.ExposeDebug();
4076
4077 // Create object with named interceptor.
4078 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
4079 named->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
4080 env->Global()->Set(v8::String::New("intercepted_named"),
4081 named->NewInstance());
4082
4083 // Create object with indexed interceptor.
4084 v8::Handle<v8::ObjectTemplate> indexed = v8::ObjectTemplate::New();
4085 indexed->SetIndexedPropertyHandler(IndexedGetter,
4086 NULL,
4087 NULL,
4088 NULL,
4089 IndexedEnum);
4090 env->Global()->Set(v8::String::New("intercepted_indexed"),
4091 indexed->NewInstance());
4092
4093 // Create object with both named and indexed interceptor.
4094 v8::Handle<v8::ObjectTemplate> both = v8::ObjectTemplate::New();
4095 both->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
4096 both->SetIndexedPropertyHandler(IndexedGetter, NULL, NULL, NULL, IndexedEnum);
4097 env->Global()->Set(v8::String::New("intercepted_both"), both->NewInstance());
4098
4099 // Get mirrors for the three objects with interceptor.
4100 CompileRun(
4101 "named_mirror = debug.MakeMirror(intercepted_named);"
4102 "indexed_mirror = debug.MakeMirror(intercepted_indexed);"
4103 "both_mirror = debug.MakeMirror(intercepted_both)");
4104 CHECK(CompileRun(
4105 "named_mirror instanceof debug.ObjectMirror")->BooleanValue());
4106 CHECK(CompileRun(
4107 "indexed_mirror instanceof debug.ObjectMirror")->BooleanValue());
4108 CHECK(CompileRun(
4109 "both_mirror instanceof debug.ObjectMirror")->BooleanValue());
4110
4111 // Get the property names from the interceptors
4112 CompileRun(
4113 "named_names = named_mirror.propertyNames();"
4114 "indexed_names = indexed_mirror.propertyNames();"
4115 "both_names = both_mirror.propertyNames()");
4116 CHECK_EQ(3, CompileRun("named_names.length")->Int32Value());
4117 CHECK_EQ(2, CompileRun("indexed_names.length")->Int32Value());
4118 CHECK_EQ(5, CompileRun("both_names.length")->Int32Value());
4119
4120 // Check the expected number of properties.
4121 const char* source;
4122 source = "named_mirror.properties().length";
4123 CHECK_EQ(3, CompileRun(source)->Int32Value());
4124
4125 source = "indexed_mirror.properties().length";
4126 CHECK_EQ(2, CompileRun(source)->Int32Value());
4127
4128 source = "both_mirror.properties().length";
4129 CHECK_EQ(5, CompileRun(source)->Int32Value());
4130
4131 // 1 is PropertyKind.Named;
4132 source = "both_mirror.properties(1).length";
4133 CHECK_EQ(3, CompileRun(source)->Int32Value());
4134
4135 // 2 is PropertyKind.Indexed;
4136 source = "both_mirror.properties(2).length";
4137 CHECK_EQ(2, CompileRun(source)->Int32Value());
4138
4139 // 3 is PropertyKind.Named | PropertyKind.Indexed;
4140 source = "both_mirror.properties(3).length";
4141 CHECK_EQ(5, CompileRun(source)->Int32Value());
4142
4143 // Get the interceptor properties for the object with only named interceptor.
4144 CompileRun("named_values = named_mirror.properties()");
4145
4146 // Check that the properties are interceptor properties.
4147 for (int i = 0; i < 3; i++) {
4148 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4149 OS::SNPrintF(buffer,
4150 "named_values[%d] instanceof debug.PropertyMirror", i);
4151 CHECK(CompileRun(buffer.start())->BooleanValue());
4152
4153 // 4 is PropertyType.Interceptor
4154 OS::SNPrintF(buffer, "named_values[%d].propertyType()", i);
4155 CHECK_EQ(4, CompileRun(buffer.start())->Int32Value());
4156
4157 OS::SNPrintF(buffer, "named_values[%d].isNative()", i);
4158 CHECK(CompileRun(buffer.start())->BooleanValue());
4159 }
4160
4161 // Get the interceptor properties for the object with only indexed
4162 // interceptor.
4163 CompileRun("indexed_values = indexed_mirror.properties()");
4164
4165 // Check that the properties are interceptor properties.
4166 for (int i = 0; i < 2; i++) {
4167 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4168 OS::SNPrintF(buffer,
4169 "indexed_values[%d] instanceof debug.PropertyMirror", i);
4170 CHECK(CompileRun(buffer.start())->BooleanValue());
4171 }
4172
4173 // Get the interceptor properties for the object with both types of
4174 // interceptors.
4175 CompileRun("both_values = both_mirror.properties()");
4176
4177 // Check that the properties are interceptor properties.
4178 for (int i = 0; i < 5; i++) {
4179 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4180 OS::SNPrintF(buffer, "both_values[%d] instanceof debug.PropertyMirror", i);
4181 CHECK(CompileRun(buffer.start())->BooleanValue());
4182 }
4183
4184 // Check the property names.
4185 source = "both_values[0].name() == 'a'";
4186 CHECK(CompileRun(source)->BooleanValue());
4187
4188 source = "both_values[1].name() == 'b'";
4189 CHECK(CompileRun(source)->BooleanValue());
4190
4191 source = "both_values[2].name() == 'c'";
4192 CHECK(CompileRun(source)->BooleanValue());
4193
4194 source = "both_values[3].name() == 1";
4195 CHECK(CompileRun(source)->BooleanValue());
4196
4197 source = "both_values[4].name() == 10";
4198 CHECK(CompileRun(source)->BooleanValue());
4199}
4200
4201
4202TEST(HiddenPrototypePropertyMirror) {
4203 // Create a V8 environment with debug access.
4204 v8::HandleScope scope;
4205 DebugLocalContext env;
4206 env.ExposeDebug();
4207
4208 v8::Handle<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
4209 t0->InstanceTemplate()->Set(v8::String::New("x"), v8::Number::New(0));
4210 v8::Handle<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
4211 t1->SetHiddenPrototype(true);
4212 t1->InstanceTemplate()->Set(v8::String::New("y"), v8::Number::New(1));
4213 v8::Handle<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
4214 t2->SetHiddenPrototype(true);
4215 t2->InstanceTemplate()->Set(v8::String::New("z"), v8::Number::New(2));
4216 v8::Handle<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
4217 t3->InstanceTemplate()->Set(v8::String::New("u"), v8::Number::New(3));
4218
4219 // Create object and set them on the global object.
4220 v8::Handle<v8::Object> o0 = t0->GetFunction()->NewInstance();
4221 env->Global()->Set(v8::String::New("o0"), o0);
4222 v8::Handle<v8::Object> o1 = t1->GetFunction()->NewInstance();
4223 env->Global()->Set(v8::String::New("o1"), o1);
4224 v8::Handle<v8::Object> o2 = t2->GetFunction()->NewInstance();
4225 env->Global()->Set(v8::String::New("o2"), o2);
4226 v8::Handle<v8::Object> o3 = t3->GetFunction()->NewInstance();
4227 env->Global()->Set(v8::String::New("o3"), o3);
4228
4229 // Get mirrors for the four objects.
4230 CompileRun(
4231 "o0_mirror = debug.MakeMirror(o0);"
4232 "o1_mirror = debug.MakeMirror(o1);"
4233 "o2_mirror = debug.MakeMirror(o2);"
4234 "o3_mirror = debug.MakeMirror(o3)");
4235 CHECK(CompileRun("o0_mirror instanceof debug.ObjectMirror")->BooleanValue());
4236 CHECK(CompileRun("o1_mirror instanceof debug.ObjectMirror")->BooleanValue());
4237 CHECK(CompileRun("o2_mirror instanceof debug.ObjectMirror")->BooleanValue());
4238 CHECK(CompileRun("o3_mirror instanceof debug.ObjectMirror")->BooleanValue());
4239
4240 // Check that each object has one property.
4241 CHECK_EQ(1, CompileRun(
4242 "o0_mirror.propertyNames().length")->Int32Value());
4243 CHECK_EQ(1, CompileRun(
4244 "o1_mirror.propertyNames().length")->Int32Value());
4245 CHECK_EQ(1, CompileRun(
4246 "o2_mirror.propertyNames().length")->Int32Value());
4247 CHECK_EQ(1, CompileRun(
4248 "o3_mirror.propertyNames().length")->Int32Value());
4249
4250 // Set o1 as prototype for o0. o1 has the hidden prototype flag so all
4251 // properties on o1 should be seen on o0.
4252 o0->Set(v8::String::New("__proto__"), o1);
4253 CHECK_EQ(2, CompileRun(
4254 "o0_mirror.propertyNames().length")->Int32Value());
4255 CHECK_EQ(0, CompileRun(
4256 "o0_mirror.property('x').value().value()")->Int32Value());
4257 CHECK_EQ(1, CompileRun(
4258 "o0_mirror.property('y').value().value()")->Int32Value());
4259
4260 // Set o2 as prototype for o0 (it will end up after o1 as o1 has the hidden
4261 // prototype flag. o2 also has the hidden prototype flag so all properties
4262 // on o2 should be seen on o0 as well as properties on o1.
4263 o0->Set(v8::String::New("__proto__"), o2);
4264 CHECK_EQ(3, CompileRun(
4265 "o0_mirror.propertyNames().length")->Int32Value());
4266 CHECK_EQ(0, CompileRun(
4267 "o0_mirror.property('x').value().value()")->Int32Value());
4268 CHECK_EQ(1, CompileRun(
4269 "o0_mirror.property('y').value().value()")->Int32Value());
4270 CHECK_EQ(2, CompileRun(
4271 "o0_mirror.property('z').value().value()")->Int32Value());
4272
4273 // Set o3 as prototype for o0 (it will end up after o1 and o2 as both o1 and
4274 // o2 has the hidden prototype flag. o3 does not have the hidden prototype
4275 // flag so properties on o3 should not be seen on o0 whereas the properties
4276 // from o1 and o2 should still be seen on o0.
4277 // Final prototype chain: o0 -> o1 -> o2 -> o3
4278 // Hidden prototypes: ^^ ^^
4279 o0->Set(v8::String::New("__proto__"), o3);
4280 CHECK_EQ(3, CompileRun(
4281 "o0_mirror.propertyNames().length")->Int32Value());
4282 CHECK_EQ(1, CompileRun(
4283 "o3_mirror.propertyNames().length")->Int32Value());
4284 CHECK_EQ(0, CompileRun(
4285 "o0_mirror.property('x').value().value()")->Int32Value());
4286 CHECK_EQ(1, CompileRun(
4287 "o0_mirror.property('y').value().value()")->Int32Value());
4288 CHECK_EQ(2, CompileRun(
4289 "o0_mirror.property('z').value().value()")->Int32Value());
4290 CHECK(CompileRun("o0_mirror.property('u').isUndefined()")->BooleanValue());
4291
4292 // The prototype (__proto__) for o0 should be o3 as o1 and o2 are hidden.
4293 CHECK(CompileRun("o0_mirror.protoObject() == o3_mirror")->BooleanValue());
4294}
4295
4296
4297static v8::Handle<v8::Value> ProtperyXNativeGetter(
4298 v8::Local<v8::String> property, const v8::AccessorInfo& info) {
4299 return v8::Integer::New(10);
4300}
4301
4302
4303TEST(NativeGetterPropertyMirror) {
4304 // Create a V8 environment with debug access.
4305 v8::HandleScope scope;
4306 DebugLocalContext env;
4307 env.ExposeDebug();
4308
4309 v8::Handle<v8::String> name = v8::String::New("x");
4310 // Create object with named accessor.
4311 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
4312 named->SetAccessor(name, &ProtperyXNativeGetter, NULL,
4313 v8::Handle<v8::Value>(), v8::DEFAULT, v8::None);
4314
4315 // Create object with named property getter.
4316 env->Global()->Set(v8::String::New("instance"), named->NewInstance());
4317 CHECK_EQ(10, CompileRun("instance.x")->Int32Value());
4318
4319 // Get mirror for the object with property getter.
4320 CompileRun("instance_mirror = debug.MakeMirror(instance);");
4321 CHECK(CompileRun(
4322 "instance_mirror instanceof debug.ObjectMirror")->BooleanValue());
4323
4324 CompileRun("named_names = instance_mirror.propertyNames();");
4325 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
4326 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue());
4327 CHECK(CompileRun(
4328 "instance_mirror.property('x').value().isNumber()")->BooleanValue());
4329 CHECK(CompileRun(
4330 "instance_mirror.property('x').value().value() == 10")->BooleanValue());
4331}
4332
4333
4334static v8::Handle<v8::Value> ProtperyXNativeGetterThrowingError(
4335 v8::Local<v8::String> property, const v8::AccessorInfo& info) {
4336 return CompileRun("throw new Error('Error message');");
4337}
4338
4339
4340TEST(NativeGetterThrowingErrorPropertyMirror) {
4341 // Create a V8 environment with debug access.
4342 v8::HandleScope scope;
4343 DebugLocalContext env;
4344 env.ExposeDebug();
4345
4346 v8::Handle<v8::String> name = v8::String::New("x");
4347 // Create object with named accessor.
4348 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
4349 named->SetAccessor(name, &ProtperyXNativeGetterThrowingError, NULL,
4350 v8::Handle<v8::Value>(), v8::DEFAULT, v8::None);
4351
4352 // Create object with named property getter.
4353 env->Global()->Set(v8::String::New("instance"), named->NewInstance());
4354
4355 // Get mirror for the object with property getter.
4356 CompileRun("instance_mirror = debug.MakeMirror(instance);");
4357 CHECK(CompileRun(
4358 "instance_mirror instanceof debug.ObjectMirror")->BooleanValue());
4359 CompileRun("named_names = instance_mirror.propertyNames();");
4360 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
4361 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue());
4362 CHECK(CompileRun(
4363 "instance_mirror.property('x').value().isError()")->BooleanValue());
4364
4365 // Check that the message is that passed to the Error constructor.
4366 CHECK(CompileRun(
4367 "instance_mirror.property('x').value().message() == 'Error message'")->
4368 BooleanValue());
4369}
4370
4371
Steve Blockd0582a62009-12-15 09:54:21 +00004372// Test that hidden properties object is not returned as an unnamed property
4373// among regular properties.
4374// See http://crbug.com/26491
4375TEST(NoHiddenProperties) {
4376 // Create a V8 environment with debug access.
4377 v8::HandleScope scope;
4378 DebugLocalContext env;
4379 env.ExposeDebug();
4380
4381 // Create an object in the global scope.
4382 const char* source = "var obj = {a: 1};";
4383 v8::Script::Compile(v8::String::New(source))->Run();
4384 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
4385 env->Global()->Get(v8::String::New("obj")));
4386 // Set a hidden property on the object.
4387 obj->SetHiddenValue(v8::String::New("v8::test-debug::a"),
4388 v8::Int32::New(11));
4389
4390 // Get mirror for the object with property getter.
4391 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
4392 CHECK(CompileRun(
4393 "obj_mirror instanceof debug.ObjectMirror")->BooleanValue());
4394 CompileRun("var named_names = obj_mirror.propertyNames();");
4395 // There should be exactly one property. But there is also an unnamed
4396 // property whose value is hidden properties dictionary. The latter
4397 // property should not be in the list of reguar properties.
4398 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
4399 CHECK(CompileRun("named_names[0] == 'a'")->BooleanValue());
4400 CHECK(CompileRun(
4401 "obj_mirror.property('a').value().value() == 1")->BooleanValue());
4402
4403 // Object created by t0 will become hidden prototype of object 'obj'.
4404 v8::Handle<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
4405 t0->InstanceTemplate()->Set(v8::String::New("b"), v8::Number::New(2));
4406 t0->SetHiddenPrototype(true);
4407 v8::Handle<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
4408 t1->InstanceTemplate()->Set(v8::String::New("c"), v8::Number::New(3));
4409
4410 // Create proto objects, add hidden properties to them and set them on
4411 // the global object.
4412 v8::Handle<v8::Object> protoObj = t0->GetFunction()->NewInstance();
4413 protoObj->SetHiddenValue(v8::String::New("v8::test-debug::b"),
4414 v8::Int32::New(12));
4415 env->Global()->Set(v8::String::New("protoObj"), protoObj);
4416 v8::Handle<v8::Object> grandProtoObj = t1->GetFunction()->NewInstance();
4417 grandProtoObj->SetHiddenValue(v8::String::New("v8::test-debug::c"),
4418 v8::Int32::New(13));
4419 env->Global()->Set(v8::String::New("grandProtoObj"), grandProtoObj);
4420
4421 // Setting prototypes: obj->protoObj->grandProtoObj
4422 protoObj->Set(v8::String::New("__proto__"), grandProtoObj);
4423 obj->Set(v8::String::New("__proto__"), protoObj);
4424
4425 // Get mirror for the object with property getter.
4426 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
4427 CHECK(CompileRun(
4428 "obj_mirror instanceof debug.ObjectMirror")->BooleanValue());
4429 CompileRun("var named_names = obj_mirror.propertyNames();");
4430 // There should be exactly two properties - one from the object itself and
4431 // another from its hidden prototype.
4432 CHECK_EQ(2, CompileRun("named_names.length")->Int32Value());
4433 CHECK(CompileRun("named_names.sort(); named_names[0] == 'a' &&"
4434 "named_names[1] == 'b'")->BooleanValue());
4435 CHECK(CompileRun(
4436 "obj_mirror.property('a').value().value() == 1")->BooleanValue());
4437 CHECK(CompileRun(
4438 "obj_mirror.property('b').value().value() == 2")->BooleanValue());
4439}
4440
Steve Blocka7e24c12009-10-30 11:49:00 +00004441
4442// Multithreaded tests of JSON debugger protocol
4443
4444// Support classes
4445
Steve Blocka7e24c12009-10-30 11:49:00 +00004446// Provides synchronization between k threads, where k is an input to the
4447// constructor. The Wait() call blocks a thread until it is called for the
4448// k'th time, then all calls return. Each ThreadBarrier object can only
4449// be used once.
4450class ThreadBarrier {
4451 public:
4452 explicit ThreadBarrier(int num_threads);
4453 ~ThreadBarrier();
4454 void Wait();
4455 private:
4456 int num_threads_;
4457 int num_blocked_;
4458 v8::internal::Mutex* lock_;
4459 v8::internal::Semaphore* sem_;
4460 bool invalid_;
4461};
4462
4463ThreadBarrier::ThreadBarrier(int num_threads)
4464 : num_threads_(num_threads), num_blocked_(0) {
4465 lock_ = OS::CreateMutex();
4466 sem_ = OS::CreateSemaphore(0);
4467 invalid_ = false; // A barrier may only be used once. Then it is invalid.
4468}
4469
4470// Do not call, due to race condition with Wait().
4471// Could be resolved with Pthread condition variables.
4472ThreadBarrier::~ThreadBarrier() {
4473 lock_->Lock();
4474 delete lock_;
4475 delete sem_;
4476}
4477
4478void ThreadBarrier::Wait() {
4479 lock_->Lock();
4480 CHECK(!invalid_);
4481 if (num_blocked_ == num_threads_ - 1) {
4482 // Signal and unblock all waiting threads.
4483 for (int i = 0; i < num_threads_ - 1; ++i) {
4484 sem_->Signal();
4485 }
4486 invalid_ = true;
4487 printf("BARRIER\n\n");
4488 fflush(stdout);
4489 lock_->Unlock();
4490 } else { // Wait for the semaphore.
4491 ++num_blocked_;
4492 lock_->Unlock(); // Potential race condition with destructor because
4493 sem_->Wait(); // these two lines are not atomic.
4494 }
4495}
4496
4497// A set containing enough barriers and semaphores for any of the tests.
4498class Barriers {
4499 public:
4500 Barriers();
4501 void Initialize();
4502 ThreadBarrier barrier_1;
4503 ThreadBarrier barrier_2;
4504 ThreadBarrier barrier_3;
4505 ThreadBarrier barrier_4;
4506 ThreadBarrier barrier_5;
4507 v8::internal::Semaphore* semaphore_1;
4508 v8::internal::Semaphore* semaphore_2;
4509};
4510
4511Barriers::Barriers() : barrier_1(2), barrier_2(2),
4512 barrier_3(2), barrier_4(2), barrier_5(2) {}
4513
4514void Barriers::Initialize() {
4515 semaphore_1 = OS::CreateSemaphore(0);
4516 semaphore_2 = OS::CreateSemaphore(0);
4517}
4518
4519
4520// We match parts of the message to decide if it is a break message.
4521bool IsBreakEventMessage(char *message) {
4522 const char* type_event = "\"type\":\"event\"";
4523 const char* event_break = "\"event\":\"break\"";
4524 // Does the message contain both type:event and event:break?
4525 return strstr(message, type_event) != NULL &&
4526 strstr(message, event_break) != NULL;
4527}
4528
4529
Steve Block3ce2e202009-11-05 08:53:23 +00004530// We match parts of the message to decide if it is a exception message.
4531bool IsExceptionEventMessage(char *message) {
4532 const char* type_event = "\"type\":\"event\"";
4533 const char* event_exception = "\"event\":\"exception\"";
4534 // Does the message contain both type:event and event:exception?
4535 return strstr(message, type_event) != NULL &&
4536 strstr(message, event_exception) != NULL;
4537}
4538
4539
4540// We match the message wether it is an evaluate response message.
4541bool IsEvaluateResponseMessage(char* message) {
4542 const char* type_response = "\"type\":\"response\"";
4543 const char* command_evaluate = "\"command\":\"evaluate\"";
4544 // Does the message contain both type:response and command:evaluate?
4545 return strstr(message, type_response) != NULL &&
4546 strstr(message, command_evaluate) != NULL;
4547}
4548
4549
Andrei Popescu402d9372010-02-26 13:31:12 +00004550static int StringToInt(const char* s) {
4551 return atoi(s); // NOLINT
4552}
4553
4554
Steve Block3ce2e202009-11-05 08:53:23 +00004555// We match parts of the message to get evaluate result int value.
4556int GetEvaluateIntResult(char *message) {
4557 const char* value = "\"value\":";
4558 char* pos = strstr(message, value);
4559 if (pos == NULL) {
4560 return -1;
4561 }
4562 int res = -1;
Andrei Popescu402d9372010-02-26 13:31:12 +00004563 res = StringToInt(pos + strlen(value));
Steve Block3ce2e202009-11-05 08:53:23 +00004564 return res;
4565}
4566
4567
4568// We match parts of the message to get hit breakpoint id.
4569int GetBreakpointIdFromBreakEventMessage(char *message) {
4570 const char* breakpoints = "\"breakpoints\":[";
4571 char* pos = strstr(message, breakpoints);
4572 if (pos == NULL) {
4573 return -1;
4574 }
4575 int res = -1;
Andrei Popescu402d9372010-02-26 13:31:12 +00004576 res = StringToInt(pos + strlen(breakpoints));
Steve Block3ce2e202009-11-05 08:53:23 +00004577 return res;
4578}
4579
4580
Leon Clarked91b9f72010-01-27 17:25:45 +00004581// We match parts of the message to get total frames number.
4582int GetTotalFramesInt(char *message) {
4583 const char* prefix = "\"totalFrames\":";
4584 char* pos = strstr(message, prefix);
4585 if (pos == NULL) {
4586 return -1;
4587 }
4588 pos += strlen(prefix);
Andrei Popescu402d9372010-02-26 13:31:12 +00004589 int res = StringToInt(pos);
Leon Clarked91b9f72010-01-27 17:25:45 +00004590 return res;
4591}
4592
4593
Iain Merrick9ac36c92010-09-13 15:29:50 +01004594// We match parts of the message to get source line.
4595int GetSourceLineFromBreakEventMessage(char *message) {
4596 const char* source_line = "\"sourceLine\":";
4597 char* pos = strstr(message, source_line);
4598 if (pos == NULL) {
4599 return -1;
4600 }
4601 int res = -1;
4602 res = StringToInt(pos + strlen(source_line));
4603 return res;
4604}
4605
Steve Blocka7e24c12009-10-30 11:49:00 +00004606/* Test MessageQueues */
4607/* Tests the message queues that hold debugger commands and
4608 * response messages to the debugger. Fills queues and makes
4609 * them grow.
4610 */
4611Barriers message_queue_barriers;
4612
4613// This is the debugger thread, that executes no v8 calls except
4614// placing JSON debugger commands in the queue.
4615class MessageQueueDebuggerThread : public v8::internal::Thread {
4616 public:
4617 void Run();
4618};
4619
4620static void MessageHandler(const uint16_t* message, int length,
4621 v8::Debug::ClientData* client_data) {
4622 static char print_buffer[1000];
4623 Utf16ToAscii(message, length, print_buffer);
4624 if (IsBreakEventMessage(print_buffer)) {
4625 // Lets test script wait until break occurs to send commands.
4626 // Signals when a break is reported.
4627 message_queue_barriers.semaphore_2->Signal();
4628 }
4629
4630 // Allow message handler to block on a semaphore, to test queueing of
4631 // messages while blocked.
4632 message_queue_barriers.semaphore_1->Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +00004633}
4634
4635void MessageQueueDebuggerThread::Run() {
4636 const int kBufferSize = 1000;
4637 uint16_t buffer_1[kBufferSize];
4638 uint16_t buffer_2[kBufferSize];
4639 const char* command_1 =
4640 "{\"seq\":117,"
4641 "\"type\":\"request\","
4642 "\"command\":\"evaluate\","
4643 "\"arguments\":{\"expression\":\"1+2\"}}";
4644 const char* command_2 =
4645 "{\"seq\":118,"
4646 "\"type\":\"request\","
4647 "\"command\":\"evaluate\","
4648 "\"arguments\":{\"expression\":\"1+a\"}}";
4649 const char* command_3 =
4650 "{\"seq\":119,"
4651 "\"type\":\"request\","
4652 "\"command\":\"evaluate\","
4653 "\"arguments\":{\"expression\":\"c.d * b\"}}";
4654 const char* command_continue =
4655 "{\"seq\":106,"
4656 "\"type\":\"request\","
4657 "\"command\":\"continue\"}";
4658 const char* command_single_step =
4659 "{\"seq\":107,"
4660 "\"type\":\"request\","
4661 "\"command\":\"continue\","
4662 "\"arguments\":{\"stepaction\":\"next\"}}";
4663
4664 /* Interleaved sequence of actions by the two threads:*/
4665 // Main thread compiles and runs source_1
4666 message_queue_barriers.semaphore_1->Signal();
4667 message_queue_barriers.barrier_1.Wait();
4668 // Post 6 commands, filling the command queue and making it expand.
4669 // These calls return immediately, but the commands stay on the queue
4670 // until the execution of source_2.
4671 // Note: AsciiToUtf16 executes before SendCommand, so command is copied
4672 // to buffer before buffer is sent to SendCommand.
4673 v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_1, buffer_1));
4674 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_2, buffer_2));
4675 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
4676 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
4677 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
4678 message_queue_barriers.barrier_2.Wait();
4679 // Main thread compiles and runs source_2.
4680 // Queued commands are executed at the start of compilation of source_2(
4681 // beforeCompile event).
4682 // Free the message handler to process all the messages from the queue. 7
4683 // messages are expected: 2 afterCompile events and 5 responses.
4684 // All the commands added so far will fail to execute as long as call stack
4685 // is empty on beforeCompile event.
4686 for (int i = 0; i < 6 ; ++i) {
4687 message_queue_barriers.semaphore_1->Signal();
4688 }
4689 message_queue_barriers.barrier_3.Wait();
4690 // Main thread compiles and runs source_3.
4691 // Don't stop in the afterCompile handler.
4692 message_queue_barriers.semaphore_1->Signal();
4693 // source_3 includes a debugger statement, which causes a break event.
4694 // Wait on break event from hitting "debugger" statement
4695 message_queue_barriers.semaphore_2->Wait();
4696 // These should execute after the "debugger" statement in source_2
4697 v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_1, buffer_1));
4698 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_2, buffer_2));
4699 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
4700 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_single_step, buffer_2));
4701 // Run after 2 break events, 4 responses.
4702 for (int i = 0; i < 6 ; ++i) {
4703 message_queue_barriers.semaphore_1->Signal();
4704 }
4705 // Wait on break event after a single step executes.
4706 message_queue_barriers.semaphore_2->Wait();
4707 v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_2, buffer_1));
4708 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_continue, buffer_2));
4709 // Run after 2 responses.
4710 for (int i = 0; i < 2 ; ++i) {
4711 message_queue_barriers.semaphore_1->Signal();
4712 }
4713 // Main thread continues running source_3 to end, waits for this thread.
4714}
4715
4716MessageQueueDebuggerThread message_queue_debugger_thread;
4717
4718// This thread runs the v8 engine.
4719TEST(MessageQueues) {
4720 // Create a V8 environment
4721 v8::HandleScope scope;
4722 DebugLocalContext env;
4723 message_queue_barriers.Initialize();
4724 v8::Debug::SetMessageHandler(MessageHandler);
4725 message_queue_debugger_thread.Start();
4726
4727 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
4728 const char* source_2 = "e = 17;";
4729 const char* source_3 = "a = 4; debugger; a = 5; a = 6; a = 7;";
4730
4731 // See MessageQueueDebuggerThread::Run for interleaved sequence of
4732 // API calls and events in the two threads.
4733 CompileRun(source_1);
4734 message_queue_barriers.barrier_1.Wait();
4735 message_queue_barriers.barrier_2.Wait();
4736 CompileRun(source_2);
4737 message_queue_barriers.barrier_3.Wait();
4738 CompileRun(source_3);
4739 message_queue_debugger_thread.Join();
4740 fflush(stdout);
4741}
4742
4743
4744class TestClientData : public v8::Debug::ClientData {
4745 public:
4746 TestClientData() {
4747 constructor_call_counter++;
4748 }
4749 virtual ~TestClientData() {
4750 destructor_call_counter++;
4751 }
4752
4753 static void ResetCounters() {
4754 constructor_call_counter = 0;
4755 destructor_call_counter = 0;
4756 }
4757
4758 static int constructor_call_counter;
4759 static int destructor_call_counter;
4760};
4761
4762int TestClientData::constructor_call_counter = 0;
4763int TestClientData::destructor_call_counter = 0;
4764
4765
4766// Tests that MessageQueue doesn't destroy client data when expands and
4767// does destroy when it dies.
4768TEST(MessageQueueExpandAndDestroy) {
4769 TestClientData::ResetCounters();
4770 { // Create a scope for the queue.
4771 CommandMessageQueue queue(1);
4772 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4773 new TestClientData()));
4774 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4775 new TestClientData()));
4776 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4777 new TestClientData()));
4778 CHECK_EQ(0, TestClientData::destructor_call_counter);
4779 queue.Get().Dispose();
4780 CHECK_EQ(1, TestClientData::destructor_call_counter);
4781 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4782 new TestClientData()));
4783 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4784 new TestClientData()));
4785 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4786 new TestClientData()));
4787 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4788 new TestClientData()));
4789 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4790 new TestClientData()));
4791 CHECK_EQ(1, TestClientData::destructor_call_counter);
4792 queue.Get().Dispose();
4793 CHECK_EQ(2, TestClientData::destructor_call_counter);
4794 }
4795 // All the client data should be destroyed when the queue is destroyed.
4796 CHECK_EQ(TestClientData::destructor_call_counter,
4797 TestClientData::destructor_call_counter);
4798}
4799
4800
4801static int handled_client_data_instances_count = 0;
4802static void MessageHandlerCountingClientData(
4803 const v8::Debug::Message& message) {
4804 if (message.GetClientData() != NULL) {
4805 handled_client_data_instances_count++;
4806 }
4807}
4808
4809
4810// Tests that all client data passed to the debugger are sent to the handler.
4811TEST(SendClientDataToHandler) {
4812 // Create a V8 environment
4813 v8::HandleScope scope;
4814 DebugLocalContext env;
4815 TestClientData::ResetCounters();
4816 handled_client_data_instances_count = 0;
4817 v8::Debug::SetMessageHandler2(MessageHandlerCountingClientData);
4818 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
4819 const int kBufferSize = 1000;
4820 uint16_t buffer[kBufferSize];
4821 const char* command_1 =
4822 "{\"seq\":117,"
4823 "\"type\":\"request\","
4824 "\"command\":\"evaluate\","
4825 "\"arguments\":{\"expression\":\"1+2\"}}";
4826 const char* command_2 =
4827 "{\"seq\":118,"
4828 "\"type\":\"request\","
4829 "\"command\":\"evaluate\","
4830 "\"arguments\":{\"expression\":\"1+a\"}}";
4831 const char* command_continue =
4832 "{\"seq\":106,"
4833 "\"type\":\"request\","
4834 "\"command\":\"continue\"}";
4835
4836 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer),
4837 new TestClientData());
4838 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer), NULL);
4839 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer),
4840 new TestClientData());
4841 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer),
4842 new TestClientData());
4843 // All the messages will be processed on beforeCompile event.
4844 CompileRun(source_1);
4845 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer));
4846 CHECK_EQ(3, TestClientData::constructor_call_counter);
4847 CHECK_EQ(TestClientData::constructor_call_counter,
4848 handled_client_data_instances_count);
4849 CHECK_EQ(TestClientData::constructor_call_counter,
4850 TestClientData::destructor_call_counter);
4851}
4852
4853
4854/* Test ThreadedDebugging */
4855/* This test interrupts a running infinite loop that is
4856 * occupying the v8 thread by a break command from the
4857 * debugger thread. It then changes the value of a
4858 * global object, to make the loop terminate.
4859 */
4860
4861Barriers threaded_debugging_barriers;
4862
4863class V8Thread : public v8::internal::Thread {
4864 public:
4865 void Run();
4866};
4867
4868class DebuggerThread : public v8::internal::Thread {
4869 public:
4870 void Run();
4871};
4872
4873
4874static v8::Handle<v8::Value> ThreadedAtBarrier1(const v8::Arguments& args) {
4875 threaded_debugging_barriers.barrier_1.Wait();
4876 return v8::Undefined();
4877}
4878
4879
4880static void ThreadedMessageHandler(const v8::Debug::Message& message) {
4881 static char print_buffer[1000];
4882 v8::String::Value json(message.GetJSON());
4883 Utf16ToAscii(*json, json.length(), print_buffer);
4884 if (IsBreakEventMessage(print_buffer)) {
Iain Merrick9ac36c92010-09-13 15:29:50 +01004885 // Check that we are inside the while loop.
4886 int source_line = GetSourceLineFromBreakEventMessage(print_buffer);
4887 CHECK(8 <= source_line && source_line <= 13);
Steve Blocka7e24c12009-10-30 11:49:00 +00004888 threaded_debugging_barriers.barrier_2.Wait();
4889 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004890}
4891
4892
4893void V8Thread::Run() {
4894 const char* source =
4895 "flag = true;\n"
4896 "function bar( new_value ) {\n"
4897 " flag = new_value;\n"
4898 " return \"Return from bar(\" + new_value + \")\";\n"
4899 "}\n"
4900 "\n"
4901 "function foo() {\n"
4902 " var x = 1;\n"
4903 " while ( flag == true ) {\n"
4904 " if ( x == 1 ) {\n"
4905 " ThreadedAtBarrier1();\n"
4906 " }\n"
4907 " x = x + 1;\n"
4908 " }\n"
4909 "}\n"
4910 "\n"
4911 "foo();\n";
4912
4913 v8::HandleScope scope;
4914 DebugLocalContext env;
4915 v8::Debug::SetMessageHandler2(&ThreadedMessageHandler);
4916 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4917 global_template->Set(v8::String::New("ThreadedAtBarrier1"),
4918 v8::FunctionTemplate::New(ThreadedAtBarrier1));
4919 v8::Handle<v8::Context> context = v8::Context::New(NULL, global_template);
4920 v8::Context::Scope context_scope(context);
4921
4922 CompileRun(source);
4923}
4924
4925void DebuggerThread::Run() {
4926 const int kBufSize = 1000;
4927 uint16_t buffer[kBufSize];
4928
4929 const char* command_1 = "{\"seq\":102,"
4930 "\"type\":\"request\","
4931 "\"command\":\"evaluate\","
4932 "\"arguments\":{\"expression\":\"bar(false)\"}}";
4933 const char* command_2 = "{\"seq\":103,"
4934 "\"type\":\"request\","
4935 "\"command\":\"continue\"}";
4936
4937 threaded_debugging_barriers.barrier_1.Wait();
4938 v8::Debug::DebugBreak();
4939 threaded_debugging_barriers.barrier_2.Wait();
4940 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
4941 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
4942}
4943
4944DebuggerThread debugger_thread;
4945V8Thread v8_thread;
4946
4947TEST(ThreadedDebugging) {
4948 // Create a V8 environment
4949 threaded_debugging_barriers.Initialize();
4950
4951 v8_thread.Start();
4952 debugger_thread.Start();
4953
4954 v8_thread.Join();
4955 debugger_thread.Join();
4956}
4957
4958/* Test RecursiveBreakpoints */
4959/* In this test, the debugger evaluates a function with a breakpoint, after
4960 * hitting a breakpoint in another function. We do this with both values
4961 * of the flag enabling recursive breakpoints, and verify that the second
4962 * breakpoint is hit when enabled, and missed when disabled.
4963 */
4964
4965class BreakpointsV8Thread : public v8::internal::Thread {
4966 public:
4967 void Run();
4968};
4969
4970class BreakpointsDebuggerThread : public v8::internal::Thread {
4971 public:
Leon Clarked91b9f72010-01-27 17:25:45 +00004972 explicit BreakpointsDebuggerThread(bool global_evaluate)
4973 : global_evaluate_(global_evaluate) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00004974 void Run();
Leon Clarked91b9f72010-01-27 17:25:45 +00004975
4976 private:
4977 bool global_evaluate_;
Steve Blocka7e24c12009-10-30 11:49:00 +00004978};
4979
4980
4981Barriers* breakpoints_barriers;
Steve Block3ce2e202009-11-05 08:53:23 +00004982int break_event_breakpoint_id;
4983int evaluate_int_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00004984
4985static void BreakpointsMessageHandler(const v8::Debug::Message& message) {
4986 static char print_buffer[1000];
4987 v8::String::Value json(message.GetJSON());
4988 Utf16ToAscii(*json, json.length(), print_buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00004989
Steve Blocka7e24c12009-10-30 11:49:00 +00004990 if (IsBreakEventMessage(print_buffer)) {
Steve Block3ce2e202009-11-05 08:53:23 +00004991 break_event_breakpoint_id =
4992 GetBreakpointIdFromBreakEventMessage(print_buffer);
4993 breakpoints_barriers->semaphore_1->Signal();
4994 } else if (IsEvaluateResponseMessage(print_buffer)) {
4995 evaluate_int_result = GetEvaluateIntResult(print_buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00004996 breakpoints_barriers->semaphore_1->Signal();
4997 }
4998}
4999
5000
5001void BreakpointsV8Thread::Run() {
5002 const char* source_1 = "var y_global = 3;\n"
5003 "function cat( new_value ) {\n"
5004 " var x = new_value;\n"
Steve Block3ce2e202009-11-05 08:53:23 +00005005 " y_global = y_global + 4;\n"
Steve Blocka7e24c12009-10-30 11:49:00 +00005006 " x = 3 * x + 1;\n"
Steve Block3ce2e202009-11-05 08:53:23 +00005007 " y_global = y_global + 5;\n"
Steve Blocka7e24c12009-10-30 11:49:00 +00005008 " return x;\n"
5009 "}\n"
5010 "\n"
5011 "function dog() {\n"
5012 " var x = 1;\n"
5013 " x = y_global;"
5014 " var z = 3;"
5015 " x += 100;\n"
5016 " return x;\n"
5017 "}\n"
5018 "\n";
5019 const char* source_2 = "cat(17);\n"
5020 "cat(19);\n";
5021
5022 v8::HandleScope scope;
5023 DebugLocalContext env;
5024 v8::Debug::SetMessageHandler2(&BreakpointsMessageHandler);
5025
5026 CompileRun(source_1);
5027 breakpoints_barriers->barrier_1.Wait();
5028 breakpoints_barriers->barrier_2.Wait();
5029 CompileRun(source_2);
5030}
5031
5032
5033void BreakpointsDebuggerThread::Run() {
5034 const int kBufSize = 1000;
5035 uint16_t buffer[kBufSize];
5036
5037 const char* command_1 = "{\"seq\":101,"
5038 "\"type\":\"request\","
5039 "\"command\":\"setbreakpoint\","
5040 "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}";
5041 const char* command_2 = "{\"seq\":102,"
5042 "\"type\":\"request\","
5043 "\"command\":\"setbreakpoint\","
5044 "\"arguments\":{\"type\":\"function\",\"target\":\"dog\",\"line\":3}}";
Leon Clarked91b9f72010-01-27 17:25:45 +00005045 const char* command_3;
5046 if (this->global_evaluate_) {
5047 command_3 = "{\"seq\":103,"
5048 "\"type\":\"request\","
5049 "\"command\":\"evaluate\","
5050 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false,"
5051 "\"global\":true}}";
5052 } else {
5053 command_3 = "{\"seq\":103,"
5054 "\"type\":\"request\","
5055 "\"command\":\"evaluate\","
5056 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false}}";
5057 }
5058 const char* command_4;
5059 if (this->global_evaluate_) {
5060 command_4 = "{\"seq\":104,"
5061 "\"type\":\"request\","
5062 "\"command\":\"evaluate\","
5063 "\"arguments\":{\"expression\":\"100 + 8\",\"disable_break\":true,"
5064 "\"global\":true}}";
5065 } else {
5066 command_4 = "{\"seq\":104,"
5067 "\"type\":\"request\","
5068 "\"command\":\"evaluate\","
5069 "\"arguments\":{\"expression\":\"x + 1\",\"disable_break\":true}}";
5070 }
Steve Block3ce2e202009-11-05 08:53:23 +00005071 const char* command_5 = "{\"seq\":105,"
Steve Blocka7e24c12009-10-30 11:49:00 +00005072 "\"type\":\"request\","
5073 "\"command\":\"continue\"}";
Steve Block3ce2e202009-11-05 08:53:23 +00005074 const char* command_6 = "{\"seq\":106,"
Steve Blocka7e24c12009-10-30 11:49:00 +00005075 "\"type\":\"request\","
5076 "\"command\":\"continue\"}";
Leon Clarked91b9f72010-01-27 17:25:45 +00005077 const char* command_7;
5078 if (this->global_evaluate_) {
5079 command_7 = "{\"seq\":107,"
5080 "\"type\":\"request\","
5081 "\"command\":\"evaluate\","
5082 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true,"
5083 "\"global\":true}}";
5084 } else {
5085 command_7 = "{\"seq\":107,"
5086 "\"type\":\"request\","
5087 "\"command\":\"evaluate\","
5088 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true}}";
5089 }
Steve Block3ce2e202009-11-05 08:53:23 +00005090 const char* command_8 = "{\"seq\":108,"
Steve Blocka7e24c12009-10-30 11:49:00 +00005091 "\"type\":\"request\","
5092 "\"command\":\"continue\"}";
5093
5094
5095 // v8 thread initializes, runs source_1
5096 breakpoints_barriers->barrier_1.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005097 // 1:Set breakpoint in cat() (will get id 1).
Steve Blocka7e24c12009-10-30 11:49:00 +00005098 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005099 // 2:Set breakpoint in dog() (will get id 2).
Steve Blocka7e24c12009-10-30 11:49:00 +00005100 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
5101 breakpoints_barriers->barrier_2.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005102 // V8 thread starts compiling source_2.
Steve Blocka7e24c12009-10-30 11:49:00 +00005103 // Automatic break happens, to run queued commands
5104 // breakpoints_barriers->semaphore_1->Wait();
5105 // Commands 1 through 3 run, thread continues.
5106 // v8 thread runs source_2 to breakpoint in cat().
5107 // message callback receives break event.
5108 breakpoints_barriers->semaphore_1->Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005109 // Must have hit breakpoint #1.
5110 CHECK_EQ(1, break_event_breakpoint_id);
Steve Blocka7e24c12009-10-30 11:49:00 +00005111 // 4:Evaluate dog() (which has a breakpoint).
5112 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_3, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005113 // V8 thread hits breakpoint in dog().
Steve Blocka7e24c12009-10-30 11:49:00 +00005114 breakpoints_barriers->semaphore_1->Wait(); // wait for break event
Steve Block3ce2e202009-11-05 08:53:23 +00005115 // Must have hit breakpoint #2.
5116 CHECK_EQ(2, break_event_breakpoint_id);
5117 // 5:Evaluate (x + 1).
Steve Blocka7e24c12009-10-30 11:49:00 +00005118 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_4, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005119 // Evaluate (x + 1) finishes.
5120 breakpoints_barriers->semaphore_1->Wait();
5121 // Must have result 108.
5122 CHECK_EQ(108, evaluate_int_result);
5123 // 6:Continue evaluation of dog().
Steve Blocka7e24c12009-10-30 11:49:00 +00005124 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_5, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005125 // Evaluate dog() finishes.
5126 breakpoints_barriers->semaphore_1->Wait();
5127 // Must have result 107.
5128 CHECK_EQ(107, evaluate_int_result);
Steve Blocka7e24c12009-10-30 11:49:00 +00005129 // 7:Continue evaluation of source_2, finish cat(17), hit breakpoint
5130 // in cat(19).
5131 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_6, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005132 // Message callback gets break event.
Steve Blocka7e24c12009-10-30 11:49:00 +00005133 breakpoints_barriers->semaphore_1->Wait(); // wait for break event
Steve Block3ce2e202009-11-05 08:53:23 +00005134 // Must have hit breakpoint #1.
5135 CHECK_EQ(1, break_event_breakpoint_id);
5136 // 8: Evaluate dog() with breaks disabled.
Steve Blocka7e24c12009-10-30 11:49:00 +00005137 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_7, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005138 // Evaluate dog() finishes.
5139 breakpoints_barriers->semaphore_1->Wait();
5140 // Must have result 116.
5141 CHECK_EQ(116, evaluate_int_result);
Steve Blocka7e24c12009-10-30 11:49:00 +00005142 // 9: Continue evaluation of source2, reach end.
5143 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_8, buffer));
5144}
5145
Leon Clarked91b9f72010-01-27 17:25:45 +00005146void TestRecursiveBreakpointsGeneric(bool global_evaluate) {
Leon Clarkeeab96aa2010-01-27 16:31:12 +00005147 i::FLAG_debugger_auto_break = true;
Leon Clarke888f6722010-01-27 15:57:47 +00005148
Leon Clarked91b9f72010-01-27 17:25:45 +00005149 BreakpointsDebuggerThread breakpoints_debugger_thread(global_evaluate);
5150 BreakpointsV8Thread breakpoints_v8_thread;
5151
Steve Blocka7e24c12009-10-30 11:49:00 +00005152 // Create a V8 environment
5153 Barriers stack_allocated_breakpoints_barriers;
5154 stack_allocated_breakpoints_barriers.Initialize();
5155 breakpoints_barriers = &stack_allocated_breakpoints_barriers;
5156
5157 breakpoints_v8_thread.Start();
5158 breakpoints_debugger_thread.Start();
5159
5160 breakpoints_v8_thread.Join();
5161 breakpoints_debugger_thread.Join();
5162}
5163
Leon Clarked91b9f72010-01-27 17:25:45 +00005164TEST(RecursiveBreakpoints) {
5165 TestRecursiveBreakpointsGeneric(false);
5166}
5167
5168TEST(RecursiveBreakpointsGlobal) {
5169 TestRecursiveBreakpointsGeneric(true);
5170}
5171
Steve Blocka7e24c12009-10-30 11:49:00 +00005172
5173static void DummyDebugEventListener(v8::DebugEvent event,
5174 v8::Handle<v8::Object> exec_state,
5175 v8::Handle<v8::Object> event_data,
5176 v8::Handle<v8::Value> data) {
5177}
5178
5179
5180TEST(SetDebugEventListenerOnUninitializedVM) {
5181 v8::Debug::SetDebugEventListener(DummyDebugEventListener);
5182}
5183
5184
5185static void DummyMessageHandler(const v8::Debug::Message& message) {
5186}
5187
5188
5189TEST(SetMessageHandlerOnUninitializedVM) {
5190 v8::Debug::SetMessageHandler2(DummyMessageHandler);
5191}
5192
5193
5194TEST(DebugBreakOnUninitializedVM) {
5195 v8::Debug::DebugBreak();
5196}
5197
5198
5199TEST(SendCommandToUninitializedVM) {
5200 const char* dummy_command = "{}";
5201 uint16_t dummy_buffer[80];
5202 int dummy_length = AsciiToUtf16(dummy_command, dummy_buffer);
5203 v8::Debug::SendCommand(dummy_buffer, dummy_length);
5204}
5205
5206
5207// Source for a JavaScript function which returns the data parameter of a
5208// function called in the context of the debugger. If no data parameter is
5209// passed it throws an exception.
5210static const char* debugger_call_with_data_source =
5211 "function debugger_call_with_data(exec_state, data) {"
5212 " if (data) return data;"
5213 " throw 'No data!'"
5214 "}";
5215v8::Handle<v8::Function> debugger_call_with_data;
5216
5217
5218// Source for a JavaScript function which returns the data parameter of a
5219// function called in the context of the debugger. If no data parameter is
5220// passed it throws an exception.
5221static const char* debugger_call_with_closure_source =
5222 "var x = 3;"
5223 "(function (exec_state) {"
5224 " if (exec_state.y) return x - 1;"
5225 " exec_state.y = x;"
5226 " return exec_state.y"
5227 "})";
5228v8::Handle<v8::Function> debugger_call_with_closure;
5229
5230// Function to retrieve the number of JavaScript frames by calling a JavaScript
5231// in the debugger.
5232static v8::Handle<v8::Value> CheckFrameCount(const v8::Arguments& args) {
5233 CHECK(v8::Debug::Call(frame_count)->IsNumber());
5234 CHECK_EQ(args[0]->Int32Value(),
5235 v8::Debug::Call(frame_count)->Int32Value());
5236 return v8::Undefined();
5237}
5238
5239
5240// Function to retrieve the source line of the top JavaScript frame by calling a
5241// JavaScript function in the debugger.
5242static v8::Handle<v8::Value> CheckSourceLine(const v8::Arguments& args) {
5243 CHECK(v8::Debug::Call(frame_source_line)->IsNumber());
5244 CHECK_EQ(args[0]->Int32Value(),
5245 v8::Debug::Call(frame_source_line)->Int32Value());
5246 return v8::Undefined();
5247}
5248
5249
5250// Function to test passing an additional parameter to a JavaScript function
5251// called in the debugger. It also tests that functions called in the debugger
5252// can throw exceptions.
5253static v8::Handle<v8::Value> CheckDataParameter(const v8::Arguments& args) {
5254 v8::Handle<v8::String> data = v8::String::New("Test");
5255 CHECK(v8::Debug::Call(debugger_call_with_data, data)->IsString());
5256
5257 CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
5258 CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
5259
5260 v8::TryCatch catcher;
5261 v8::Debug::Call(debugger_call_with_data);
5262 CHECK(catcher.HasCaught());
5263 CHECK(catcher.Exception()->IsString());
5264
5265 return v8::Undefined();
5266}
5267
5268
5269// Function to test using a JavaScript with closure in the debugger.
5270static v8::Handle<v8::Value> CheckClosure(const v8::Arguments& args) {
5271 CHECK(v8::Debug::Call(debugger_call_with_closure)->IsNumber());
5272 CHECK_EQ(3, v8::Debug::Call(debugger_call_with_closure)->Int32Value());
5273 return v8::Undefined();
5274}
5275
5276
5277// Test functions called through the debugger.
5278TEST(CallFunctionInDebugger) {
5279 // Create and enter a context with the functions CheckFrameCount,
5280 // CheckSourceLine and CheckDataParameter installed.
5281 v8::HandleScope scope;
5282 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5283 global_template->Set(v8::String::New("CheckFrameCount"),
5284 v8::FunctionTemplate::New(CheckFrameCount));
5285 global_template->Set(v8::String::New("CheckSourceLine"),
5286 v8::FunctionTemplate::New(CheckSourceLine));
5287 global_template->Set(v8::String::New("CheckDataParameter"),
5288 v8::FunctionTemplate::New(CheckDataParameter));
5289 global_template->Set(v8::String::New("CheckClosure"),
5290 v8::FunctionTemplate::New(CheckClosure));
5291 v8::Handle<v8::Context> context = v8::Context::New(NULL, global_template);
5292 v8::Context::Scope context_scope(context);
5293
5294 // Compile a function for checking the number of JavaScript frames.
5295 v8::Script::Compile(v8::String::New(frame_count_source))->Run();
5296 frame_count = v8::Local<v8::Function>::Cast(
5297 context->Global()->Get(v8::String::New("frame_count")));
5298
5299 // Compile a function for returning the source line for the top frame.
5300 v8::Script::Compile(v8::String::New(frame_source_line_source))->Run();
5301 frame_source_line = v8::Local<v8::Function>::Cast(
5302 context->Global()->Get(v8::String::New("frame_source_line")));
5303
5304 // Compile a function returning the data parameter.
5305 v8::Script::Compile(v8::String::New(debugger_call_with_data_source))->Run();
5306 debugger_call_with_data = v8::Local<v8::Function>::Cast(
5307 context->Global()->Get(v8::String::New("debugger_call_with_data")));
5308
5309 // Compile a function capturing closure.
5310 debugger_call_with_closure = v8::Local<v8::Function>::Cast(
5311 v8::Script::Compile(
5312 v8::String::New(debugger_call_with_closure_source))->Run());
5313
Steve Block6ded16b2010-05-10 14:33:55 +01005314 // Calling a function through the debugger returns 0 frames if there are
5315 // no JavaScript frames.
5316 CHECK_EQ(v8::Integer::New(0), v8::Debug::Call(frame_count));
Steve Blocka7e24c12009-10-30 11:49:00 +00005317
5318 // Test that the number of frames can be retrieved.
5319 v8::Script::Compile(v8::String::New("CheckFrameCount(1)"))->Run();
5320 v8::Script::Compile(v8::String::New("function f() {"
5321 " CheckFrameCount(2);"
5322 "}; f()"))->Run();
5323
5324 // Test that the source line can be retrieved.
5325 v8::Script::Compile(v8::String::New("CheckSourceLine(0)"))->Run();
5326 v8::Script::Compile(v8::String::New("function f() {\n"
5327 " CheckSourceLine(1)\n"
5328 " CheckSourceLine(2)\n"
5329 " CheckSourceLine(3)\n"
5330 "}; f()"))->Run();
5331
5332 // Test that a parameter can be passed to a function called in the debugger.
5333 v8::Script::Compile(v8::String::New("CheckDataParameter()"))->Run();
5334
5335 // Test that a function with closure can be run in the debugger.
5336 v8::Script::Compile(v8::String::New("CheckClosure()"))->Run();
5337
5338
5339 // Test that the source line is correct when there is a line offset.
5340 v8::ScriptOrigin origin(v8::String::New("test"),
5341 v8::Integer::New(7));
5342 v8::Script::Compile(v8::String::New("CheckSourceLine(7)"), &origin)->Run();
5343 v8::Script::Compile(v8::String::New("function f() {\n"
5344 " CheckSourceLine(8)\n"
5345 " CheckSourceLine(9)\n"
5346 " CheckSourceLine(10)\n"
5347 "}; f()"), &origin)->Run();
5348}
5349
5350
5351// Debugger message handler which counts the number of breaks.
5352static void SendContinueCommand();
5353static void MessageHandlerBreakPointHitCount(
5354 const v8::Debug::Message& message) {
5355 if (message.IsEvent() && message.GetEvent() == v8::Break) {
5356 // Count the number of breaks.
5357 break_point_hit_count++;
5358
5359 SendContinueCommand();
5360 }
5361}
5362
5363
5364// Test that clearing the debug event listener actually clears all break points
5365// and related information.
5366TEST(DebuggerUnload) {
5367 DebugLocalContext env;
5368
5369 // Check debugger is unloaded before it is used.
5370 CheckDebuggerUnloaded();
5371
5372 // Set a debug event listener.
5373 break_point_hit_count = 0;
5374 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
5375 v8::Undefined());
5376 {
5377 v8::HandleScope scope;
5378 // Create a couple of functions for the test.
5379 v8::Local<v8::Function> foo =
5380 CompileFunction(&env, "function foo(){x=1}", "foo");
5381 v8::Local<v8::Function> bar =
5382 CompileFunction(&env, "function bar(){y=2}", "bar");
5383
5384 // Set some break points.
5385 SetBreakPoint(foo, 0);
5386 SetBreakPoint(foo, 4);
5387 SetBreakPoint(bar, 0);
5388 SetBreakPoint(bar, 4);
5389
5390 // Make sure that the break points are there.
5391 break_point_hit_count = 0;
5392 foo->Call(env->Global(), 0, NULL);
5393 CHECK_EQ(2, break_point_hit_count);
5394 bar->Call(env->Global(), 0, NULL);
5395 CHECK_EQ(4, break_point_hit_count);
5396 }
5397
5398 // Remove the debug event listener without clearing breakpoints. Do this
5399 // outside a handle scope.
5400 v8::Debug::SetDebugEventListener(NULL);
5401 CheckDebuggerUnloaded(true);
5402
5403 // Now set a debug message handler.
5404 break_point_hit_count = 0;
5405 v8::Debug::SetMessageHandler2(MessageHandlerBreakPointHitCount);
5406 {
5407 v8::HandleScope scope;
5408
5409 // Get the test functions again.
5410 v8::Local<v8::Function> foo =
5411 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
5412 v8::Local<v8::Function> bar =
5413 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
5414
5415 foo->Call(env->Global(), 0, NULL);
5416 CHECK_EQ(0, break_point_hit_count);
5417
5418 // Set break points and run again.
5419 SetBreakPoint(foo, 0);
5420 SetBreakPoint(foo, 4);
5421 foo->Call(env->Global(), 0, NULL);
5422 CHECK_EQ(2, break_point_hit_count);
5423 }
5424
5425 // Remove the debug message handler without clearing breakpoints. Do this
5426 // outside a handle scope.
5427 v8::Debug::SetMessageHandler2(NULL);
5428 CheckDebuggerUnloaded(true);
5429}
5430
5431
5432// Sends continue command to the debugger.
5433static void SendContinueCommand() {
5434 const int kBufferSize = 1000;
5435 uint16_t buffer[kBufferSize];
5436 const char* command_continue =
5437 "{\"seq\":0,"
5438 "\"type\":\"request\","
5439 "\"command\":\"continue\"}";
5440
5441 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer));
5442}
5443
5444
5445// Debugger message handler which counts the number of times it is called.
5446static int message_handler_hit_count = 0;
5447static void MessageHandlerHitCount(const v8::Debug::Message& message) {
5448 message_handler_hit_count++;
5449
Steve Block3ce2e202009-11-05 08:53:23 +00005450 static char print_buffer[1000];
5451 v8::String::Value json(message.GetJSON());
5452 Utf16ToAscii(*json, json.length(), print_buffer);
5453 if (IsExceptionEventMessage(print_buffer)) {
5454 // Send a continue command for exception events.
5455 SendContinueCommand();
5456 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005457}
5458
5459
5460// Test clearing the debug message handler.
5461TEST(DebuggerClearMessageHandler) {
5462 v8::HandleScope scope;
5463 DebugLocalContext env;
5464
5465 // Check debugger is unloaded before it is used.
5466 CheckDebuggerUnloaded();
5467
5468 // Set a debug message handler.
5469 v8::Debug::SetMessageHandler2(MessageHandlerHitCount);
5470
5471 // Run code to throw a unhandled exception. This should end up in the message
5472 // handler.
5473 CompileRun("throw 1");
5474
5475 // The message handler should be called.
5476 CHECK_GT(message_handler_hit_count, 0);
5477
5478 // Clear debug message handler.
5479 message_handler_hit_count = 0;
5480 v8::Debug::SetMessageHandler(NULL);
5481
5482 // Run code to throw a unhandled exception. This should end up in the message
5483 // handler.
5484 CompileRun("throw 1");
5485
5486 // The message handler should not be called more.
5487 CHECK_EQ(0, message_handler_hit_count);
5488
5489 CheckDebuggerUnloaded(true);
5490}
5491
5492
5493// Debugger message handler which clears the message handler while active.
5494static void MessageHandlerClearingMessageHandler(
5495 const v8::Debug::Message& message) {
5496 message_handler_hit_count++;
5497
5498 // Clear debug message handler.
5499 v8::Debug::SetMessageHandler(NULL);
5500}
5501
5502
5503// Test clearing the debug message handler while processing a debug event.
5504TEST(DebuggerClearMessageHandlerWhileActive) {
5505 v8::HandleScope scope;
5506 DebugLocalContext env;
5507
5508 // Check debugger is unloaded before it is used.
5509 CheckDebuggerUnloaded();
5510
5511 // Set a debug message handler.
5512 v8::Debug::SetMessageHandler2(MessageHandlerClearingMessageHandler);
5513
5514 // Run code to throw a unhandled exception. This should end up in the message
5515 // handler.
5516 CompileRun("throw 1");
5517
5518 // The message handler should be called.
5519 CHECK_EQ(1, message_handler_hit_count);
5520
5521 CheckDebuggerUnloaded(true);
5522}
5523
5524
5525/* Test DebuggerHostDispatch */
5526/* In this test, the debugger waits for a command on a breakpoint
5527 * and is dispatching host commands while in the infinite loop.
5528 */
5529
5530class HostDispatchV8Thread : public v8::internal::Thread {
5531 public:
5532 void Run();
5533};
5534
5535class HostDispatchDebuggerThread : public v8::internal::Thread {
5536 public:
5537 void Run();
5538};
5539
5540Barriers* host_dispatch_barriers;
5541
5542static void HostDispatchMessageHandler(const v8::Debug::Message& message) {
5543 static char print_buffer[1000];
5544 v8::String::Value json(message.GetJSON());
5545 Utf16ToAscii(*json, json.length(), print_buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00005546}
5547
5548
5549static void HostDispatchDispatchHandler() {
5550 host_dispatch_barriers->semaphore_1->Signal();
5551}
5552
5553
5554void HostDispatchV8Thread::Run() {
5555 const char* source_1 = "var y_global = 3;\n"
5556 "function cat( new_value ) {\n"
5557 " var x = new_value;\n"
5558 " y_global = 4;\n"
5559 " x = 3 * x + 1;\n"
5560 " y_global = 5;\n"
5561 " return x;\n"
5562 "}\n"
5563 "\n";
5564 const char* source_2 = "cat(17);\n";
5565
5566 v8::HandleScope scope;
5567 DebugLocalContext env;
5568
5569 // Setup message and host dispatch handlers.
5570 v8::Debug::SetMessageHandler2(HostDispatchMessageHandler);
5571 v8::Debug::SetHostDispatchHandler(HostDispatchDispatchHandler, 10 /* ms */);
5572
5573 CompileRun(source_1);
5574 host_dispatch_barriers->barrier_1.Wait();
5575 host_dispatch_barriers->barrier_2.Wait();
5576 CompileRun(source_2);
5577}
5578
5579
5580void HostDispatchDebuggerThread::Run() {
5581 const int kBufSize = 1000;
5582 uint16_t buffer[kBufSize];
5583
5584 const char* command_1 = "{\"seq\":101,"
5585 "\"type\":\"request\","
5586 "\"command\":\"setbreakpoint\","
5587 "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}";
5588 const char* command_2 = "{\"seq\":102,"
5589 "\"type\":\"request\","
5590 "\"command\":\"continue\"}";
5591
5592 // v8 thread initializes, runs source_1
5593 host_dispatch_barriers->barrier_1.Wait();
5594 // 1: Set breakpoint in cat().
5595 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
5596
5597 host_dispatch_barriers->barrier_2.Wait();
5598 // v8 thread starts compiling source_2.
5599 // Break happens, to run queued commands and host dispatches.
5600 // Wait for host dispatch to be processed.
5601 host_dispatch_barriers->semaphore_1->Wait();
5602 // 2: Continue evaluation
5603 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
5604}
5605
5606HostDispatchDebuggerThread host_dispatch_debugger_thread;
5607HostDispatchV8Thread host_dispatch_v8_thread;
5608
5609
5610TEST(DebuggerHostDispatch) {
5611 i::FLAG_debugger_auto_break = true;
5612
5613 // Create a V8 environment
5614 Barriers stack_allocated_host_dispatch_barriers;
5615 stack_allocated_host_dispatch_barriers.Initialize();
5616 host_dispatch_barriers = &stack_allocated_host_dispatch_barriers;
5617
5618 host_dispatch_v8_thread.Start();
5619 host_dispatch_debugger_thread.Start();
5620
5621 host_dispatch_v8_thread.Join();
5622 host_dispatch_debugger_thread.Join();
5623}
5624
5625
Steve Blockd0582a62009-12-15 09:54:21 +00005626/* Test DebugMessageDispatch */
5627/* In this test, the V8 thread waits for a message from the debug thread.
5628 * The DebugMessageDispatchHandler is executed from the debugger thread
5629 * which signals the V8 thread to wake up.
5630 */
5631
5632class DebugMessageDispatchV8Thread : public v8::internal::Thread {
5633 public:
5634 void Run();
5635};
5636
5637class DebugMessageDispatchDebuggerThread : public v8::internal::Thread {
5638 public:
5639 void Run();
5640};
5641
5642Barriers* debug_message_dispatch_barriers;
5643
5644
5645static void DebugMessageHandler() {
5646 debug_message_dispatch_barriers->semaphore_1->Signal();
5647}
5648
5649
5650void DebugMessageDispatchV8Thread::Run() {
5651 v8::HandleScope scope;
5652 DebugLocalContext env;
5653
5654 // Setup debug message dispatch handler.
5655 v8::Debug::SetDebugMessageDispatchHandler(DebugMessageHandler);
5656
5657 CompileRun("var y = 1 + 2;\n");
5658 debug_message_dispatch_barriers->barrier_1.Wait();
5659 debug_message_dispatch_barriers->semaphore_1->Wait();
5660 debug_message_dispatch_barriers->barrier_2.Wait();
5661}
5662
5663
5664void DebugMessageDispatchDebuggerThread::Run() {
5665 debug_message_dispatch_barriers->barrier_1.Wait();
5666 SendContinueCommand();
5667 debug_message_dispatch_barriers->barrier_2.Wait();
5668}
5669
5670DebugMessageDispatchDebuggerThread debug_message_dispatch_debugger_thread;
5671DebugMessageDispatchV8Thread debug_message_dispatch_v8_thread;
5672
5673
5674TEST(DebuggerDebugMessageDispatch) {
5675 i::FLAG_debugger_auto_break = true;
5676
5677 // Create a V8 environment
5678 Barriers stack_allocated_debug_message_dispatch_barriers;
5679 stack_allocated_debug_message_dispatch_barriers.Initialize();
5680 debug_message_dispatch_barriers =
5681 &stack_allocated_debug_message_dispatch_barriers;
5682
5683 debug_message_dispatch_v8_thread.Start();
5684 debug_message_dispatch_debugger_thread.Start();
5685
5686 debug_message_dispatch_v8_thread.Join();
5687 debug_message_dispatch_debugger_thread.Join();
5688}
5689
5690
Steve Blocka7e24c12009-10-30 11:49:00 +00005691TEST(DebuggerAgent) {
5692 // Make sure these ports is not used by other tests to allow tests to run in
5693 // parallel.
5694 const int kPort1 = 5858;
5695 const int kPort2 = 5857;
5696 const int kPort3 = 5856;
5697
5698 // Make a string with the port2 number.
5699 const int kPortBufferLen = 6;
5700 char port2_str[kPortBufferLen];
5701 OS::SNPrintF(i::Vector<char>(port2_str, kPortBufferLen), "%d", kPort2);
5702
5703 bool ok;
5704
5705 // Initialize the socket library.
5706 i::Socket::Setup();
5707
5708 // Test starting and stopping the agent without any client connection.
5709 i::Debugger::StartAgent("test", kPort1);
5710 i::Debugger::StopAgent();
5711
5712 // Test starting the agent, connecting a client and shutting down the agent
5713 // with the client connected.
5714 ok = i::Debugger::StartAgent("test", kPort2);
5715 CHECK(ok);
5716 i::Debugger::WaitForAgent();
5717 i::Socket* client = i::OS::CreateSocket();
5718 ok = client->Connect("localhost", port2_str);
5719 CHECK(ok);
5720 i::Debugger::StopAgent();
5721 delete client;
5722
5723 // Test starting and stopping the agent with the required port already
5724 // occoupied.
5725 i::Socket* server = i::OS::CreateSocket();
5726 server->Bind(kPort3);
5727
5728 i::Debugger::StartAgent("test", kPort3);
5729 i::Debugger::StopAgent();
5730
5731 delete server;
5732}
5733
5734
5735class DebuggerAgentProtocolServerThread : public i::Thread {
5736 public:
5737 explicit DebuggerAgentProtocolServerThread(int port)
5738 : port_(port), server_(NULL), client_(NULL),
5739 listening_(OS::CreateSemaphore(0)) {
5740 }
5741 ~DebuggerAgentProtocolServerThread() {
5742 // Close both sockets.
5743 delete client_;
5744 delete server_;
5745 delete listening_;
5746 }
5747
5748 void Run();
5749 void WaitForListening() { listening_->Wait(); }
5750 char* body() { return *body_; }
5751
5752 private:
5753 int port_;
5754 i::SmartPointer<char> body_;
5755 i::Socket* server_; // Server socket used for bind/accept.
5756 i::Socket* client_; // Single client connection used by the test.
5757 i::Semaphore* listening_; // Signalled when the server is in listen mode.
5758};
5759
5760
5761void DebuggerAgentProtocolServerThread::Run() {
5762 bool ok;
5763
5764 // Create the server socket and bind it to the requested port.
5765 server_ = i::OS::CreateSocket();
5766 CHECK(server_ != NULL);
5767 ok = server_->Bind(port_);
5768 CHECK(ok);
5769
5770 // Listen for new connections.
5771 ok = server_->Listen(1);
5772 CHECK(ok);
5773 listening_->Signal();
5774
5775 // Accept a connection.
5776 client_ = server_->Accept();
5777 CHECK(client_ != NULL);
5778
5779 // Receive a debugger agent protocol message.
5780 i::DebuggerAgentUtil::ReceiveMessage(client_);
5781}
5782
5783
5784TEST(DebuggerAgentProtocolOverflowHeader) {
5785 // Make sure this port is not used by other tests to allow tests to run in
5786 // parallel.
5787 const int kPort = 5860;
5788 static const char* kLocalhost = "localhost";
5789
5790 // Make a string with the port number.
5791 const int kPortBufferLen = 6;
5792 char port_str[kPortBufferLen];
5793 OS::SNPrintF(i::Vector<char>(port_str, kPortBufferLen), "%d", kPort);
5794
5795 // Initialize the socket library.
5796 i::Socket::Setup();
5797
5798 // Create a socket server to receive a debugger agent message.
5799 DebuggerAgentProtocolServerThread* server =
5800 new DebuggerAgentProtocolServerThread(kPort);
5801 server->Start();
5802 server->WaitForListening();
5803
5804 // Connect.
5805 i::Socket* client = i::OS::CreateSocket();
5806 CHECK(client != NULL);
5807 bool ok = client->Connect(kLocalhost, port_str);
5808 CHECK(ok);
5809
5810 // Send headers which overflow the receive buffer.
5811 static const int kBufferSize = 1000;
5812 char buffer[kBufferSize];
5813
5814 // Long key and short value: XXXX....XXXX:0\r\n.
5815 for (int i = 0; i < kBufferSize - 4; i++) {
5816 buffer[i] = 'X';
5817 }
5818 buffer[kBufferSize - 4] = ':';
5819 buffer[kBufferSize - 3] = '0';
5820 buffer[kBufferSize - 2] = '\r';
5821 buffer[kBufferSize - 1] = '\n';
5822 client->Send(buffer, kBufferSize);
5823
5824 // Short key and long value: X:XXXX....XXXX\r\n.
5825 buffer[0] = 'X';
5826 buffer[1] = ':';
5827 for (int i = 2; i < kBufferSize - 2; i++) {
5828 buffer[i] = 'X';
5829 }
5830 buffer[kBufferSize - 2] = '\r';
5831 buffer[kBufferSize - 1] = '\n';
5832 client->Send(buffer, kBufferSize);
5833
5834 // Add empty body to request.
5835 const char* content_length_zero_header = "Content-Length:0\r\n";
Steve Blockd0582a62009-12-15 09:54:21 +00005836 client->Send(content_length_zero_header,
5837 StrLength(content_length_zero_header));
Steve Blocka7e24c12009-10-30 11:49:00 +00005838 client->Send("\r\n", 2);
5839
5840 // Wait until data is received.
5841 server->Join();
5842
5843 // Check for empty body.
5844 CHECK(server->body() == NULL);
5845
5846 // Close the client before the server to avoid TIME_WAIT issues.
5847 client->Shutdown();
5848 delete client;
5849 delete server;
5850}
5851
5852
5853// Test for issue http://code.google.com/p/v8/issues/detail?id=289.
5854// Make sure that DebugGetLoadedScripts doesn't return scripts
5855// with disposed external source.
5856class EmptyExternalStringResource : public v8::String::ExternalStringResource {
5857 public:
5858 EmptyExternalStringResource() { empty_[0] = 0; }
5859 virtual ~EmptyExternalStringResource() {}
5860 virtual size_t length() const { return empty_.length(); }
5861 virtual const uint16_t* data() const { return empty_.start(); }
5862 private:
5863 ::v8::internal::EmbeddedVector<uint16_t, 1> empty_;
5864};
5865
5866
5867TEST(DebugGetLoadedScripts) {
5868 v8::HandleScope scope;
5869 DebugLocalContext env;
5870 env.ExposeDebug();
5871
5872 EmptyExternalStringResource source_ext_str;
5873 v8::Local<v8::String> source = v8::String::NewExternal(&source_ext_str);
5874 v8::Handle<v8::Script> evil_script = v8::Script::Compile(source);
5875 Handle<i::ExternalTwoByteString> i_source(
5876 i::ExternalTwoByteString::cast(*v8::Utils::OpenHandle(*source)));
5877 // This situation can happen if source was an external string disposed
5878 // by its owner.
5879 i_source->set_resource(0);
5880
5881 bool allow_natives_syntax = i::FLAG_allow_natives_syntax;
5882 i::FLAG_allow_natives_syntax = true;
5883 CompileRun(
5884 "var scripts = %DebugGetLoadedScripts();"
5885 "var count = scripts.length;"
5886 "for (var i = 0; i < count; ++i) {"
5887 " scripts[i].line_ends;"
5888 "}");
5889 // Must not crash while accessing line_ends.
5890 i::FLAG_allow_natives_syntax = allow_natives_syntax;
5891
5892 // Some scripts are retrieved - at least the number of native scripts.
5893 CHECK_GT((*env)->Global()->Get(v8::String::New("count"))->Int32Value(), 8);
5894}
5895
5896
5897// Test script break points set on lines.
5898TEST(ScriptNameAndData) {
5899 v8::HandleScope scope;
5900 DebugLocalContext env;
5901 env.ExposeDebug();
5902
5903 // Create functions for retrieving script name and data for the function on
5904 // the top frame when hitting a break point.
5905 frame_script_name = CompileFunction(&env,
5906 frame_script_name_source,
5907 "frame_script_name");
5908 frame_script_data = CompileFunction(&env,
5909 frame_script_data_source,
5910 "frame_script_data");
Andrei Popescu402d9372010-02-26 13:31:12 +00005911 compiled_script_data = CompileFunction(&env,
5912 compiled_script_data_source,
5913 "compiled_script_data");
Steve Blocka7e24c12009-10-30 11:49:00 +00005914
5915 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
5916 v8::Undefined());
5917
5918 // Test function source.
5919 v8::Local<v8::String> script = v8::String::New(
5920 "function f() {\n"
5921 " debugger;\n"
5922 "}\n");
5923
5924 v8::ScriptOrigin origin1 = v8::ScriptOrigin(v8::String::New("name"));
5925 v8::Handle<v8::Script> script1 = v8::Script::Compile(script, &origin1);
5926 script1->SetData(v8::String::New("data"));
5927 script1->Run();
5928 v8::Local<v8::Function> f;
5929 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
5930
5931 f->Call(env->Global(), 0, NULL);
5932 CHECK_EQ(1, break_point_hit_count);
5933 CHECK_EQ("name", last_script_name_hit);
5934 CHECK_EQ("data", last_script_data_hit);
5935
5936 // Compile the same script again without setting data. As the compilation
5937 // cache is disabled when debugging expect the data to be missing.
5938 v8::Script::Compile(script, &origin1)->Run();
5939 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
5940 f->Call(env->Global(), 0, NULL);
5941 CHECK_EQ(2, break_point_hit_count);
5942 CHECK_EQ("name", last_script_name_hit);
5943 CHECK_EQ("", last_script_data_hit); // Undefined results in empty string.
5944
5945 v8::Local<v8::String> data_obj_source = v8::String::New(
5946 "({ a: 'abc',\n"
5947 " b: 123,\n"
5948 " toString: function() { return this.a + ' ' + this.b; }\n"
5949 "})\n");
5950 v8::Local<v8::Value> data_obj = v8::Script::Compile(data_obj_source)->Run();
5951 v8::ScriptOrigin origin2 = v8::ScriptOrigin(v8::String::New("new name"));
5952 v8::Handle<v8::Script> script2 = v8::Script::Compile(script, &origin2);
5953 script2->Run();
Steve Blockd0582a62009-12-15 09:54:21 +00005954 script2->SetData(data_obj->ToString());
Steve Blocka7e24c12009-10-30 11:49:00 +00005955 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
5956 f->Call(env->Global(), 0, NULL);
5957 CHECK_EQ(3, break_point_hit_count);
5958 CHECK_EQ("new name", last_script_name_hit);
5959 CHECK_EQ("abc 123", last_script_data_hit);
Andrei Popescu402d9372010-02-26 13:31:12 +00005960
5961 v8::Handle<v8::Script> script3 =
5962 v8::Script::Compile(script, &origin2, NULL,
5963 v8::String::New("in compile"));
5964 CHECK_EQ("in compile", last_script_data_hit);
5965 script3->Run();
5966 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
5967 f->Call(env->Global(), 0, NULL);
5968 CHECK_EQ(4, break_point_hit_count);
5969 CHECK_EQ("in compile", last_script_data_hit);
Steve Blocka7e24c12009-10-30 11:49:00 +00005970}
5971
5972
5973static v8::Persistent<v8::Context> expected_context;
5974static v8::Handle<v8::Value> expected_context_data;
5975
5976
5977// Check that the expected context is the one generating the debug event.
5978static void ContextCheckMessageHandler(const v8::Debug::Message& message) {
5979 CHECK(message.GetEventContext() == expected_context);
5980 CHECK(message.GetEventContext()->GetData()->StrictEquals(
5981 expected_context_data));
5982 message_handler_hit_count++;
5983
Steve Block3ce2e202009-11-05 08:53:23 +00005984 static char print_buffer[1000];
5985 v8::String::Value json(message.GetJSON());
5986 Utf16ToAscii(*json, json.length(), print_buffer);
5987
Steve Blocka7e24c12009-10-30 11:49:00 +00005988 // Send a continue command for break events.
Steve Block3ce2e202009-11-05 08:53:23 +00005989 if (IsBreakEventMessage(print_buffer)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005990 SendContinueCommand();
5991 }
5992}
5993
5994
5995// Test which creates two contexts and sets different embedder data on each.
5996// Checks that this data is set correctly and that when the debug message
5997// handler is called the expected context is the one active.
5998TEST(ContextData) {
5999 v8::HandleScope scope;
6000
6001 v8::Debug::SetMessageHandler2(ContextCheckMessageHandler);
6002
6003 // Create two contexts.
6004 v8::Persistent<v8::Context> context_1;
6005 v8::Persistent<v8::Context> context_2;
6006 v8::Handle<v8::ObjectTemplate> global_template =
6007 v8::Handle<v8::ObjectTemplate>();
6008 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>();
6009 context_1 = v8::Context::New(NULL, global_template, global_object);
6010 context_2 = v8::Context::New(NULL, global_template, global_object);
6011
6012 // Default data value is undefined.
6013 CHECK(context_1->GetData()->IsUndefined());
6014 CHECK(context_2->GetData()->IsUndefined());
6015
6016 // Set and check different data values.
Steve Blockd0582a62009-12-15 09:54:21 +00006017 v8::Handle<v8::String> data_1 = v8::String::New("1");
6018 v8::Handle<v8::String> data_2 = v8::String::New("2");
Steve Blocka7e24c12009-10-30 11:49:00 +00006019 context_1->SetData(data_1);
6020 context_2->SetData(data_2);
6021 CHECK(context_1->GetData()->StrictEquals(data_1));
6022 CHECK(context_2->GetData()->StrictEquals(data_2));
6023
6024 // Simple test function which causes a break.
6025 const char* source = "function f() { debugger; }";
6026
6027 // Enter and run function in the first context.
6028 {
6029 v8::Context::Scope context_scope(context_1);
6030 expected_context = context_1;
6031 expected_context_data = data_1;
6032 v8::Local<v8::Function> f = CompileFunction(source, "f");
6033 f->Call(context_1->Global(), 0, NULL);
6034 }
6035
6036
6037 // Enter and run function in the second context.
6038 {
6039 v8::Context::Scope context_scope(context_2);
6040 expected_context = context_2;
6041 expected_context_data = data_2;
6042 v8::Local<v8::Function> f = CompileFunction(source, "f");
6043 f->Call(context_2->Global(), 0, NULL);
6044 }
6045
6046 // Two times compile event and two times break event.
6047 CHECK_GT(message_handler_hit_count, 4);
6048
6049 v8::Debug::SetMessageHandler2(NULL);
6050 CheckDebuggerUnloaded();
6051}
6052
6053
6054// Debug message handler which issues a debug break when it hits a break event.
6055static int message_handler_break_hit_count = 0;
6056static void DebugBreakMessageHandler(const v8::Debug::Message& message) {
6057 // Schedule a debug break for break events.
6058 if (message.IsEvent() && message.GetEvent() == v8::Break) {
6059 message_handler_break_hit_count++;
6060 if (message_handler_break_hit_count == 1) {
6061 v8::Debug::DebugBreak();
6062 }
6063 }
6064
6065 // Issue a continue command if this event will not cause the VM to start
6066 // running.
6067 if (!message.WillStartRunning()) {
6068 SendContinueCommand();
6069 }
6070}
6071
6072
6073// Test that a debug break can be scheduled while in a message handler.
6074TEST(DebugBreakInMessageHandler) {
6075 v8::HandleScope scope;
6076 DebugLocalContext env;
6077
6078 v8::Debug::SetMessageHandler2(DebugBreakMessageHandler);
6079
6080 // Test functions.
6081 const char* script = "function f() { debugger; g(); } function g() { }";
6082 CompileRun(script);
6083 v8::Local<v8::Function> f =
6084 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6085 v8::Local<v8::Function> g =
6086 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
6087
6088 // Call f then g. The debugger statement in f will casue a break which will
6089 // cause another break.
6090 f->Call(env->Global(), 0, NULL);
6091 CHECK_EQ(2, message_handler_break_hit_count);
6092 // Calling g will not cause any additional breaks.
6093 g->Call(env->Global(), 0, NULL);
6094 CHECK_EQ(2, message_handler_break_hit_count);
6095}
6096
6097
Steve Block6ded16b2010-05-10 14:33:55 +01006098#ifndef V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +00006099// Debug event handler which gets the function on the top frame and schedules a
6100// break a number of times.
6101static void DebugEventDebugBreak(
6102 v8::DebugEvent event,
6103 v8::Handle<v8::Object> exec_state,
6104 v8::Handle<v8::Object> event_data,
6105 v8::Handle<v8::Value> data) {
6106
6107 if (event == v8::Break) {
6108 break_point_hit_count++;
6109
6110 // Get the name of the top frame function.
6111 if (!frame_function_name.IsEmpty()) {
6112 // Get the name of the function.
6113 const int argc = 1;
6114 v8::Handle<v8::Value> argv[argc] = { exec_state };
6115 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
6116 argc, argv);
6117 if (result->IsUndefined()) {
6118 last_function_hit[0] = '\0';
6119 } else {
6120 CHECK(result->IsString());
6121 v8::Handle<v8::String> function_name(result->ToString());
6122 function_name->WriteAscii(last_function_hit);
6123 }
6124 }
6125
6126 // Keep forcing breaks.
6127 if (break_point_hit_count < 20) {
6128 v8::Debug::DebugBreak();
6129 }
6130 }
6131}
6132
6133
6134TEST(RegExpDebugBreak) {
6135 // This test only applies to native regexps.
6136 v8::HandleScope scope;
6137 DebugLocalContext env;
6138
6139 // Create a function for checking the function when hitting a break point.
6140 frame_function_name = CompileFunction(&env,
6141 frame_function_name_source,
6142 "frame_function_name");
6143
6144 // Test RegExp which matches white spaces and comments at the begining of a
6145 // source line.
6146 const char* script =
6147 "var sourceLineBeginningSkip = /^(?:[ \\v\\h]*(?:\\/\\*.*?\\*\\/)*)*/;\n"
6148 "function f(s) { return s.match(sourceLineBeginningSkip)[0].length; }";
6149
6150 v8::Local<v8::Function> f = CompileFunction(script, "f");
6151 const int argc = 1;
6152 v8::Handle<v8::Value> argv[argc] = { v8::String::New(" /* xxx */ a=0;") };
6153 v8::Local<v8::Value> result = f->Call(env->Global(), argc, argv);
6154 CHECK_EQ(12, result->Int32Value());
6155
6156 v8::Debug::SetDebugEventListener(DebugEventDebugBreak);
6157 v8::Debug::DebugBreak();
6158 result = f->Call(env->Global(), argc, argv);
6159
6160 // Check that there was only one break event. Matching RegExp should not
6161 // cause Break events.
6162 CHECK_EQ(1, break_point_hit_count);
6163 CHECK_EQ("f", last_function_hit);
6164}
Steve Block6ded16b2010-05-10 14:33:55 +01006165#endif // V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +00006166
6167
6168// Common part of EvalContextData and NestedBreakEventContextData tests.
6169static void ExecuteScriptForContextCheck() {
6170 // Create a context.
6171 v8::Persistent<v8::Context> context_1;
6172 v8::Handle<v8::ObjectTemplate> global_template =
6173 v8::Handle<v8::ObjectTemplate>();
6174 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>();
6175 context_1 = v8::Context::New(NULL, global_template, global_object);
6176
6177 // Default data value is undefined.
6178 CHECK(context_1->GetData()->IsUndefined());
6179
6180 // Set and check a data value.
Steve Blockd0582a62009-12-15 09:54:21 +00006181 v8::Handle<v8::String> data_1 = v8::String::New("1");
Steve Blocka7e24c12009-10-30 11:49:00 +00006182 context_1->SetData(data_1);
6183 CHECK(context_1->GetData()->StrictEquals(data_1));
6184
6185 // Simple test function with eval that causes a break.
6186 const char* source = "function f() { eval('debugger;'); }";
6187
6188 // Enter and run function in the context.
6189 {
6190 v8::Context::Scope context_scope(context_1);
6191 expected_context = context_1;
6192 expected_context_data = data_1;
6193 v8::Local<v8::Function> f = CompileFunction(source, "f");
6194 f->Call(context_1->Global(), 0, NULL);
6195 }
6196}
6197
6198
6199// Test which creates a context and sets embedder data on it. Checks that this
6200// data is set correctly and that when the debug message handler is called for
6201// break event in an eval statement the expected context is the one returned by
6202// Message.GetEventContext.
6203TEST(EvalContextData) {
6204 v8::HandleScope scope;
6205 v8::Debug::SetMessageHandler2(ContextCheckMessageHandler);
6206
6207 ExecuteScriptForContextCheck();
6208
6209 // One time compile event and one time break event.
6210 CHECK_GT(message_handler_hit_count, 2);
6211 v8::Debug::SetMessageHandler2(NULL);
6212 CheckDebuggerUnloaded();
6213}
6214
6215
6216static bool sent_eval = false;
6217static int break_count = 0;
6218static int continue_command_send_count = 0;
6219// Check that the expected context is the one generating the debug event
6220// including the case of nested break event.
6221static void DebugEvalContextCheckMessageHandler(
6222 const v8::Debug::Message& message) {
6223 CHECK(message.GetEventContext() == expected_context);
6224 CHECK(message.GetEventContext()->GetData()->StrictEquals(
6225 expected_context_data));
6226 message_handler_hit_count++;
6227
Steve Block3ce2e202009-11-05 08:53:23 +00006228 static char print_buffer[1000];
6229 v8::String::Value json(message.GetJSON());
6230 Utf16ToAscii(*json, json.length(), print_buffer);
6231
6232 if (IsBreakEventMessage(print_buffer)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006233 break_count++;
6234 if (!sent_eval) {
6235 sent_eval = true;
6236
6237 const int kBufferSize = 1000;
6238 uint16_t buffer[kBufferSize];
6239 const char* eval_command =
6240 "{\"seq\":0,"
6241 "\"type\":\"request\","
6242 "\"command\":\"evaluate\","
6243 "arguments:{\"expression\":\"debugger;\","
6244 "\"global\":true,\"disable_break\":false}}";
6245
6246 // Send evaluate command.
6247 v8::Debug::SendCommand(buffer, AsciiToUtf16(eval_command, buffer));
6248 return;
6249 } else {
6250 // It's a break event caused by the evaluation request above.
6251 SendContinueCommand();
6252 continue_command_send_count++;
6253 }
Steve Block3ce2e202009-11-05 08:53:23 +00006254 } else if (IsEvaluateResponseMessage(print_buffer) &&
6255 continue_command_send_count < 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006256 // Response to the evaluation request. We're still on the breakpoint so
6257 // send continue.
6258 SendContinueCommand();
6259 continue_command_send_count++;
6260 }
6261}
6262
6263
6264// Tests that context returned for break event is correct when the event occurs
6265// in 'evaluate' debugger request.
6266TEST(NestedBreakEventContextData) {
6267 v8::HandleScope scope;
6268 break_count = 0;
6269 message_handler_hit_count = 0;
6270 v8::Debug::SetMessageHandler2(DebugEvalContextCheckMessageHandler);
6271
6272 ExecuteScriptForContextCheck();
6273
6274 // One time compile event and two times break event.
6275 CHECK_GT(message_handler_hit_count, 3);
6276
6277 // One break from the source and another from the evaluate request.
6278 CHECK_EQ(break_count, 2);
6279 v8::Debug::SetMessageHandler2(NULL);
6280 CheckDebuggerUnloaded();
6281}
6282
6283
6284// Debug event listener which counts the script collected events.
6285int script_collected_count = 0;
6286static void DebugEventScriptCollectedEvent(v8::DebugEvent event,
6287 v8::Handle<v8::Object> exec_state,
6288 v8::Handle<v8::Object> event_data,
6289 v8::Handle<v8::Value> data) {
6290 // Count the number of breaks.
6291 if (event == v8::ScriptCollected) {
6292 script_collected_count++;
6293 }
6294}
6295
6296
6297// Test that scripts collected are reported through the debug event listener.
6298TEST(ScriptCollectedEvent) {
6299 break_point_hit_count = 0;
6300 script_collected_count = 0;
6301 v8::HandleScope scope;
6302 DebugLocalContext env;
6303
6304 // Request the loaded scripts to initialize the debugger script cache.
6305 Debug::GetLoadedScripts();
6306
6307 // Do garbage collection to ensure that only the script in this test will be
6308 // collected afterwards.
6309 Heap::CollectAllGarbage(false);
6310
6311 script_collected_count = 0;
6312 v8::Debug::SetDebugEventListener(DebugEventScriptCollectedEvent,
6313 v8::Undefined());
6314 {
6315 v8::Script::Compile(v8::String::New("eval('a=1')"))->Run();
6316 v8::Script::Compile(v8::String::New("eval('a=2')"))->Run();
6317 }
6318
6319 // Do garbage collection to collect the script above which is no longer
6320 // referenced.
6321 Heap::CollectAllGarbage(false);
6322
6323 CHECK_EQ(2, script_collected_count);
6324
6325 v8::Debug::SetDebugEventListener(NULL);
6326 CheckDebuggerUnloaded();
6327}
6328
6329
6330// Debug event listener which counts the script collected events.
6331int script_collected_message_count = 0;
6332static void ScriptCollectedMessageHandler(const v8::Debug::Message& message) {
6333 // Count the number of scripts collected.
6334 if (message.IsEvent() && message.GetEvent() == v8::ScriptCollected) {
6335 script_collected_message_count++;
6336 v8::Handle<v8::Context> context = message.GetEventContext();
6337 CHECK(context.IsEmpty());
6338 }
6339}
6340
6341
6342// Test that GetEventContext doesn't fail and return empty handle for
6343// ScriptCollected events.
6344TEST(ScriptCollectedEventContext) {
6345 script_collected_message_count = 0;
6346 v8::HandleScope scope;
6347
6348 { // Scope for the DebugLocalContext.
6349 DebugLocalContext env;
6350
6351 // Request the loaded scripts to initialize the debugger script cache.
6352 Debug::GetLoadedScripts();
6353
6354 // Do garbage collection to ensure that only the script in this test will be
6355 // collected afterwards.
6356 Heap::CollectAllGarbage(false);
6357
6358 v8::Debug::SetMessageHandler2(ScriptCollectedMessageHandler);
6359 {
6360 v8::Script::Compile(v8::String::New("eval('a=1')"))->Run();
6361 v8::Script::Compile(v8::String::New("eval('a=2')"))->Run();
6362 }
6363 }
6364
6365 // Do garbage collection to collect the script above which is no longer
6366 // referenced.
6367 Heap::CollectAllGarbage(false);
6368
6369 CHECK_EQ(2, script_collected_message_count);
6370
6371 v8::Debug::SetMessageHandler2(NULL);
6372}
6373
6374
6375// Debug event listener which counts the after compile events.
6376int after_compile_message_count = 0;
6377static void AfterCompileMessageHandler(const v8::Debug::Message& message) {
6378 // Count the number of scripts collected.
6379 if (message.IsEvent()) {
6380 if (message.GetEvent() == v8::AfterCompile) {
6381 after_compile_message_count++;
6382 } else if (message.GetEvent() == v8::Break) {
6383 SendContinueCommand();
6384 }
6385 }
6386}
6387
6388
6389// Tests that after compile event is sent as many times as there are scripts
6390// compiled.
6391TEST(AfterCompileMessageWhenMessageHandlerIsReset) {
6392 v8::HandleScope scope;
6393 DebugLocalContext env;
6394 after_compile_message_count = 0;
6395 const char* script = "var a=1";
6396
6397 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6398 v8::Script::Compile(v8::String::New(script))->Run();
6399 v8::Debug::SetMessageHandler2(NULL);
6400
6401 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6402 v8::Debug::DebugBreak();
6403 v8::Script::Compile(v8::String::New(script))->Run();
6404
6405 // Setting listener to NULL should cause debugger unload.
6406 v8::Debug::SetMessageHandler2(NULL);
6407 CheckDebuggerUnloaded();
6408
6409 // Compilation cache should be disabled when debugger is active.
6410 CHECK_EQ(2, after_compile_message_count);
6411}
6412
6413
6414// Tests that break event is sent when message handler is reset.
6415TEST(BreakMessageWhenMessageHandlerIsReset) {
6416 v8::HandleScope scope;
6417 DebugLocalContext env;
6418 after_compile_message_count = 0;
6419 const char* script = "function f() {};";
6420
6421 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6422 v8::Script::Compile(v8::String::New(script))->Run();
6423 v8::Debug::SetMessageHandler2(NULL);
6424
6425 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6426 v8::Debug::DebugBreak();
6427 v8::Local<v8::Function> f =
6428 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6429 f->Call(env->Global(), 0, NULL);
6430
6431 // Setting message handler to NULL should cause debugger unload.
6432 v8::Debug::SetMessageHandler2(NULL);
6433 CheckDebuggerUnloaded();
6434
6435 // Compilation cache should be disabled when debugger is active.
6436 CHECK_EQ(1, after_compile_message_count);
6437}
6438
6439
6440static int exception_event_count = 0;
6441static void ExceptionMessageHandler(const v8::Debug::Message& message) {
6442 if (message.IsEvent() && message.GetEvent() == v8::Exception) {
6443 exception_event_count++;
6444 SendContinueCommand();
6445 }
6446}
6447
6448
6449// Tests that exception event is sent when message handler is reset.
6450TEST(ExceptionMessageWhenMessageHandlerIsReset) {
6451 v8::HandleScope scope;
6452 DebugLocalContext env;
6453 exception_event_count = 0;
6454 const char* script = "function f() {throw new Error()};";
6455
6456 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6457 v8::Script::Compile(v8::String::New(script))->Run();
6458 v8::Debug::SetMessageHandler2(NULL);
6459
6460 v8::Debug::SetMessageHandler2(ExceptionMessageHandler);
6461 v8::Local<v8::Function> f =
6462 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6463 f->Call(env->Global(), 0, NULL);
6464
6465 // Setting message handler to NULL should cause debugger unload.
6466 v8::Debug::SetMessageHandler2(NULL);
6467 CheckDebuggerUnloaded();
6468
6469 CHECK_EQ(1, exception_event_count);
6470}
6471
6472
6473// Tests after compile event is sent when there are some provisional
6474// breakpoints out of the scripts lines range.
6475TEST(ProvisionalBreakpointOnLineOutOfRange) {
6476 v8::HandleScope scope;
6477 DebugLocalContext env;
6478 env.ExposeDebug();
6479 const char* script = "function f() {};";
6480 const char* resource_name = "test_resource";
6481
6482 // Set a couple of provisional breakpoint on lines out of the script lines
6483 // range.
6484 int sbp1 = SetScriptBreakPointByNameFromJS(resource_name, 3,
6485 -1 /* no column */);
6486 int sbp2 = SetScriptBreakPointByNameFromJS(resource_name, 5, 5);
6487
6488 after_compile_message_count = 0;
6489 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6490
6491 v8::ScriptOrigin origin(
6492 v8::String::New(resource_name),
6493 v8::Integer::New(10),
6494 v8::Integer::New(1));
6495 // Compile a script whose first line number is greater than the breakpoints'
6496 // lines.
6497 v8::Script::Compile(v8::String::New(script), &origin)->Run();
6498
6499 // If the script is compiled successfully there is exactly one after compile
6500 // event. In case of an exception in debugger code after compile event is not
6501 // sent.
6502 CHECK_EQ(1, after_compile_message_count);
6503
6504 ClearBreakPointFromJS(sbp1);
6505 ClearBreakPointFromJS(sbp2);
6506 v8::Debug::SetMessageHandler2(NULL);
6507}
6508
6509
6510static void BreakMessageHandler(const v8::Debug::Message& message) {
6511 if (message.IsEvent() && message.GetEvent() == v8::Break) {
6512 // Count the number of breaks.
6513 break_point_hit_count++;
6514
6515 v8::HandleScope scope;
6516 v8::Handle<v8::String> json = message.GetJSON();
6517
6518 SendContinueCommand();
6519 } else if (message.IsEvent() && message.GetEvent() == v8::AfterCompile) {
6520 v8::HandleScope scope;
6521
6522 bool is_debug_break = i::StackGuard::IsDebugBreak();
6523 // Force DebugBreak flag while serializer is working.
6524 i::StackGuard::DebugBreak();
6525
6526 // Force serialization to trigger some internal JS execution.
6527 v8::Handle<v8::String> json = message.GetJSON();
6528
6529 // Restore previous state.
6530 if (is_debug_break) {
6531 i::StackGuard::DebugBreak();
6532 } else {
6533 i::StackGuard::Continue(i::DEBUGBREAK);
6534 }
6535 }
6536}
6537
6538
6539// Test that if DebugBreak is forced it is ignored when code from
6540// debug-delay.js is executed.
6541TEST(NoDebugBreakInAfterCompileMessageHandler) {
6542 v8::HandleScope scope;
6543 DebugLocalContext env;
6544
6545 // Register a debug event listener which sets the break flag and counts.
6546 v8::Debug::SetMessageHandler2(BreakMessageHandler);
6547
6548 // Set the debug break flag.
6549 v8::Debug::DebugBreak();
6550
6551 // Create a function for testing stepping.
6552 const char* src = "function f() { eval('var x = 10;'); } ";
6553 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
6554
6555 // There should be only one break event.
6556 CHECK_EQ(1, break_point_hit_count);
6557
6558 // Set the debug break flag again.
6559 v8::Debug::DebugBreak();
6560 f->Call(env->Global(), 0, NULL);
6561 // There should be one more break event when the script is evaluated in 'f'.
6562 CHECK_EQ(2, break_point_hit_count);
6563
6564 // Get rid of the debug message handler.
6565 v8::Debug::SetMessageHandler2(NULL);
6566 CheckDebuggerUnloaded();
6567}
6568
6569
Leon Clarkee46be812010-01-19 14:06:41 +00006570static int counting_message_handler_counter;
6571
6572static void CountingMessageHandler(const v8::Debug::Message& message) {
6573 counting_message_handler_counter++;
6574}
6575
6576// Test that debug messages get processed when ProcessDebugMessages is called.
6577TEST(ProcessDebugMessages) {
6578 v8::HandleScope scope;
6579 DebugLocalContext env;
6580
6581 counting_message_handler_counter = 0;
6582
6583 v8::Debug::SetMessageHandler2(CountingMessageHandler);
6584
6585 const int kBufferSize = 1000;
6586 uint16_t buffer[kBufferSize];
6587 const char* scripts_command =
6588 "{\"seq\":0,"
6589 "\"type\":\"request\","
6590 "\"command\":\"scripts\"}";
6591
6592 // Send scripts command.
6593 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6594
6595 CHECK_EQ(0, counting_message_handler_counter);
6596 v8::Debug::ProcessDebugMessages();
6597 // At least one message should come
6598 CHECK_GE(counting_message_handler_counter, 1);
6599
6600 counting_message_handler_counter = 0;
6601
6602 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6603 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6604 CHECK_EQ(0, counting_message_handler_counter);
6605 v8::Debug::ProcessDebugMessages();
6606 // At least two messages should come
6607 CHECK_GE(counting_message_handler_counter, 2);
6608
6609 // Get rid of the debug message handler.
6610 v8::Debug::SetMessageHandler2(NULL);
6611 CheckDebuggerUnloaded();
6612}
6613
6614
Steve Block6ded16b2010-05-10 14:33:55 +01006615struct BacktraceData {
Leon Clarked91b9f72010-01-27 17:25:45 +00006616 static int frame_counter;
6617 static void MessageHandler(const v8::Debug::Message& message) {
6618 char print_buffer[1000];
6619 v8::String::Value json(message.GetJSON());
6620 Utf16ToAscii(*json, json.length(), print_buffer, 1000);
6621
6622 if (strstr(print_buffer, "backtrace") == NULL) {
6623 return;
6624 }
6625 frame_counter = GetTotalFramesInt(print_buffer);
6626 }
6627};
6628
Steve Block6ded16b2010-05-10 14:33:55 +01006629int BacktraceData::frame_counter;
Leon Clarked91b9f72010-01-27 17:25:45 +00006630
6631
6632// Test that debug messages get processed when ProcessDebugMessages is called.
6633TEST(Backtrace) {
6634 v8::HandleScope scope;
6635 DebugLocalContext env;
6636
Steve Block6ded16b2010-05-10 14:33:55 +01006637 v8::Debug::SetMessageHandler2(BacktraceData::MessageHandler);
Leon Clarked91b9f72010-01-27 17:25:45 +00006638
6639 const int kBufferSize = 1000;
6640 uint16_t buffer[kBufferSize];
6641 const char* scripts_command =
6642 "{\"seq\":0,"
6643 "\"type\":\"request\","
6644 "\"command\":\"backtrace\"}";
6645
6646 // Check backtrace from ProcessDebugMessages.
Steve Block6ded16b2010-05-10 14:33:55 +01006647 BacktraceData::frame_counter = -10;
Leon Clarked91b9f72010-01-27 17:25:45 +00006648 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6649 v8::Debug::ProcessDebugMessages();
Steve Block6ded16b2010-05-10 14:33:55 +01006650 CHECK_EQ(BacktraceData::frame_counter, 0);
Leon Clarked91b9f72010-01-27 17:25:45 +00006651
6652 v8::Handle<v8::String> void0 = v8::String::New("void(0)");
6653 v8::Handle<v8::Script> script = v8::Script::Compile(void0, void0);
6654
6655 // Check backtrace from "void(0)" script.
Steve Block6ded16b2010-05-10 14:33:55 +01006656 BacktraceData::frame_counter = -10;
Leon Clarked91b9f72010-01-27 17:25:45 +00006657 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6658 script->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01006659 CHECK_EQ(BacktraceData::frame_counter, 1);
Leon Clarked91b9f72010-01-27 17:25:45 +00006660
6661 // Get rid of the debug message handler.
6662 v8::Debug::SetMessageHandler2(NULL);
6663 CheckDebuggerUnloaded();
6664}
6665
6666
Steve Blocka7e24c12009-10-30 11:49:00 +00006667TEST(GetMirror) {
6668 v8::HandleScope scope;
6669 DebugLocalContext env;
6670 v8::Handle<v8::Value> obj = v8::Debug::GetMirror(v8::String::New("hodja"));
6671 v8::Handle<v8::Function> run_test = v8::Handle<v8::Function>::Cast(
6672 v8::Script::New(
6673 v8::String::New(
6674 "function runTest(mirror) {"
6675 " return mirror.isString() && (mirror.length() == 5);"
6676 "}"
6677 ""
6678 "runTest;"))->Run());
6679 v8::Handle<v8::Value> result = run_test->Call(env->Global(), 1, &obj);
6680 CHECK(result->IsTrue());
6681}
Steve Blockd0582a62009-12-15 09:54:21 +00006682
6683
6684// Test that the debug break flag works with function.apply.
6685TEST(DebugBreakFunctionApply) {
6686 v8::HandleScope scope;
6687 DebugLocalContext env;
6688
6689 // Create a function for testing breaking in apply.
6690 v8::Local<v8::Function> foo = CompileFunction(
6691 &env,
6692 "function baz(x) { }"
6693 "function bar(x) { baz(); }"
6694 "function foo(){ bar.apply(this, [1]); }",
6695 "foo");
6696
6697 // Register a debug event listener which steps and counts.
6698 v8::Debug::SetDebugEventListener(DebugEventBreakMax);
6699
6700 // Set the debug break flag before calling the code using function.apply.
6701 v8::Debug::DebugBreak();
6702
6703 // Limit the number of debug breaks. This is a regression test for issue 493
6704 // where this test would enter an infinite loop.
6705 break_point_hit_count = 0;
6706 max_break_point_hit_count = 10000; // 10000 => infinite loop.
6707 foo->Call(env->Global(), 0, NULL);
6708
6709 // When keeping the debug break several break will happen.
6710 CHECK_EQ(3, break_point_hit_count);
6711
6712 v8::Debug::SetDebugEventListener(NULL);
6713 CheckDebuggerUnloaded();
6714}
6715
6716
6717v8::Handle<v8::Context> debugee_context;
6718v8::Handle<v8::Context> debugger_context;
6719
6720
6721// Property getter that checks that current and calling contexts
6722// are both the debugee contexts.
6723static v8::Handle<v8::Value> NamedGetterWithCallingContextCheck(
6724 v8::Local<v8::String> name,
6725 const v8::AccessorInfo& info) {
6726 CHECK_EQ(0, strcmp(*v8::String::AsciiValue(name), "a"));
6727 v8::Handle<v8::Context> current = v8::Context::GetCurrent();
6728 CHECK(current == debugee_context);
6729 CHECK(current != debugger_context);
6730 v8::Handle<v8::Context> calling = v8::Context::GetCalling();
6731 CHECK(calling == debugee_context);
6732 CHECK(calling != debugger_context);
6733 return v8::Int32::New(1);
6734}
6735
6736
6737// Debug event listener that checks if the first argument of a function is
6738// an object with property 'a' == 1. If the property has custom accessor
6739// this handler will eventually invoke it.
6740static void DebugEventGetAtgumentPropertyValue(
6741 v8::DebugEvent event,
6742 v8::Handle<v8::Object> exec_state,
6743 v8::Handle<v8::Object> event_data,
6744 v8::Handle<v8::Value> data) {
6745 if (event == v8::Break) {
6746 break_point_hit_count++;
6747 CHECK(debugger_context == v8::Context::GetCurrent());
6748 v8::Handle<v8::Function> func(v8::Function::Cast(*CompileRun(
6749 "(function(exec_state) {\n"
6750 " return (exec_state.frame(0).argumentValue(0).property('a').\n"
6751 " value().value() == 1);\n"
6752 "})")));
6753 const int argc = 1;
6754 v8::Handle<v8::Value> argv[argc] = { exec_state };
6755 v8::Handle<v8::Value> result = func->Call(exec_state, argc, argv);
6756 CHECK(result->IsTrue());
6757 }
6758}
6759
6760
6761TEST(CallingContextIsNotDebugContext) {
6762 // Create and enter a debugee context.
6763 v8::HandleScope scope;
6764 DebugLocalContext env;
6765 env.ExposeDebug();
6766
6767 // Save handles to the debugger and debugee contexts to be used in
6768 // NamedGetterWithCallingContextCheck.
6769 debugee_context = v8::Local<v8::Context>(*env);
6770 debugger_context = v8::Utils::ToLocal(Debug::debug_context());
6771
6772 // Create object with 'a' property accessor.
6773 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
6774 named->SetAccessor(v8::String::New("a"),
6775 NamedGetterWithCallingContextCheck);
6776 env->Global()->Set(v8::String::New("obj"),
6777 named->NewInstance());
6778
6779 // Register the debug event listener
6780 v8::Debug::SetDebugEventListener(DebugEventGetAtgumentPropertyValue);
6781
6782 // Create a function that invokes debugger.
6783 v8::Local<v8::Function> foo = CompileFunction(
6784 &env,
6785 "function bar(x) { debugger; }"
6786 "function foo(){ bar(obj); }",
6787 "foo");
6788
6789 break_point_hit_count = 0;
6790 foo->Call(env->Global(), 0, NULL);
6791 CHECK_EQ(1, break_point_hit_count);
6792
6793 v8::Debug::SetDebugEventListener(NULL);
6794 debugee_context = v8::Handle<v8::Context>();
6795 debugger_context = v8::Handle<v8::Context>();
6796 CheckDebuggerUnloaded();
6797}
Steve Block6ded16b2010-05-10 14:33:55 +01006798
6799
6800TEST(DebugContextIsPreservedBetweenAccesses) {
6801 v8::HandleScope scope;
6802 v8::Local<v8::Context> context1 = v8::Debug::GetDebugContext();
6803 v8::Local<v8::Context> context2 = v8::Debug::GetDebugContext();
6804 CHECK_EQ(*context1, *context2);
Leon Clarkef7060e22010-06-03 12:02:55 +01006805}
6806
6807
6808static v8::Handle<v8::Value> expected_callback_data;
6809static void DebugEventContextChecker(const v8::Debug::EventDetails& details) {
6810 CHECK(details.GetEventContext() == expected_context);
6811 CHECK_EQ(expected_callback_data, details.GetCallbackData());
6812}
6813
6814// Check that event details contain context where debug event occured.
6815TEST(DebugEventContext) {
6816 v8::HandleScope scope;
6817 expected_callback_data = v8::Int32::New(2010);
6818 v8::Debug::SetDebugEventListener2(DebugEventContextChecker,
6819 expected_callback_data);
6820 expected_context = v8::Context::New();
6821 v8::Context::Scope context_scope(expected_context);
6822 v8::Script::Compile(v8::String::New("(function(){debugger;})();"))->Run();
6823 expected_context.Dispose();
6824 expected_context.Clear();
6825 v8::Debug::SetDebugEventListener(NULL);
6826 expected_context_data = v8::Handle<v8::Value>();
Steve Block6ded16b2010-05-10 14:33:55 +01006827 CheckDebuggerUnloaded();
6828}
Leon Clarkef7060e22010-06-03 12:02:55 +01006829
Ben Murdoch3bec4d22010-07-22 14:51:16 +01006830
6831static void* expected_break_data;
6832static bool was_debug_break_called;
6833static bool was_debug_event_called;
6834static void DebugEventBreakDataChecker(const v8::Debug::EventDetails& details) {
6835 if (details.GetEvent() == v8::BreakForCommand) {
6836 CHECK_EQ(expected_break_data, details.GetClientData());
6837 was_debug_event_called = true;
6838 } else if (details.GetEvent() == v8::Break) {
6839 was_debug_break_called = true;
6840 }
6841}
6842
6843// Check that event details contain context where debug event occured.
6844TEST(DebugEventBreakData) {
6845 v8::HandleScope scope;
6846 DebugLocalContext env;
6847 v8::Debug::SetDebugEventListener2(DebugEventBreakDataChecker);
6848
6849 TestClientData::constructor_call_counter = 0;
6850 TestClientData::destructor_call_counter = 0;
6851
6852 expected_break_data = NULL;
6853 was_debug_event_called = false;
6854 was_debug_break_called = false;
6855 v8::Debug::DebugBreakForCommand();
6856 v8::Script::Compile(v8::String::New("(function(x){return x;})(1);"))->Run();
6857 CHECK(was_debug_event_called);
6858 CHECK(!was_debug_break_called);
6859
6860 TestClientData* data1 = new TestClientData();
6861 expected_break_data = data1;
6862 was_debug_event_called = false;
6863 was_debug_break_called = false;
6864 v8::Debug::DebugBreakForCommand(data1);
6865 v8::Script::Compile(v8::String::New("(function(x){return x+1;})(1);"))->Run();
6866 CHECK(was_debug_event_called);
6867 CHECK(!was_debug_break_called);
6868
6869 expected_break_data = NULL;
6870 was_debug_event_called = false;
6871 was_debug_break_called = false;
6872 v8::Debug::DebugBreak();
6873 v8::Script::Compile(v8::String::New("(function(x){return x+2;})(1);"))->Run();
6874 CHECK(!was_debug_event_called);
6875 CHECK(was_debug_break_called);
6876
6877 TestClientData* data2 = new TestClientData();
6878 expected_break_data = data2;
6879 was_debug_event_called = false;
6880 was_debug_break_called = false;
6881 v8::Debug::DebugBreak();
6882 v8::Debug::DebugBreakForCommand(data2);
6883 v8::Script::Compile(v8::String::New("(function(x){return x+3;})(1);"))->Run();
6884 CHECK(was_debug_event_called);
6885 CHECK(was_debug_break_called);
6886
6887 CHECK_EQ(2, TestClientData::constructor_call_counter);
6888 CHECK_EQ(TestClientData::constructor_call_counter,
6889 TestClientData::destructor_call_counter);
6890
6891 v8::Debug::SetDebugEventListener(NULL);
6892 CheckDebuggerUnloaded();
6893}
6894
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01006895#endif // ENABLE_DEBUGGER_SUPPORT