blob: 1e93bf594f1b6c3b48380c7eadc04e0a26db50c9 [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 {
872 // Mark sweep (and perhaps compact).
873 Heap::CollectAllGarbage(false);
874 }
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
1130 // Run with breakpoint
1131 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
1147// Test that a break point can be set at a return store location.
1148TEST(BreakPointReturn) {
1149 break_point_hit_count = 0;
1150 v8::HandleScope scope;
1151 DebugLocalContext env;
1152
1153 // Create a functions for checking the source line and column when hitting
1154 // a break point.
1155 frame_source_line = CompileFunction(&env,
1156 frame_source_line_source,
1157 "frame_source_line");
1158 frame_source_column = CompileFunction(&env,
1159 frame_source_column_source,
1160 "frame_source_column");
1161
1162
1163 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1164 v8::Undefined());
1165 v8::Script::Compile(v8::String::New("function foo(){}"))->Run();
1166 v8::Local<v8::Function> foo =
1167 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1168
1169 // Run without breakpoints.
1170 foo->Call(env->Global(), 0, NULL);
1171 CHECK_EQ(0, break_point_hit_count);
1172
1173 // Run with breakpoint
1174 int bp = SetBreakPoint(foo, 0);
1175 foo->Call(env->Global(), 0, NULL);
1176 CHECK_EQ(1, break_point_hit_count);
1177 CHECK_EQ(0, last_source_line);
Ben Murdochbb769b22010-08-11 14:56:33 +01001178 CHECK_EQ(15, last_source_column);
Steve Blocka7e24c12009-10-30 11:49:00 +00001179 foo->Call(env->Global(), 0, NULL);
1180 CHECK_EQ(2, break_point_hit_count);
1181 CHECK_EQ(0, last_source_line);
Ben Murdochbb769b22010-08-11 14:56:33 +01001182 CHECK_EQ(15, last_source_column);
Steve Blocka7e24c12009-10-30 11:49:00 +00001183
1184 // Run without breakpoints.
1185 ClearBreakPoint(bp);
1186 foo->Call(env->Global(), 0, NULL);
1187 CHECK_EQ(2, break_point_hit_count);
1188
1189 v8::Debug::SetDebugEventListener(NULL);
1190 CheckDebuggerUnloaded();
1191}
1192
1193
1194static void CallWithBreakPoints(v8::Local<v8::Object> recv,
1195 v8::Local<v8::Function> f,
1196 int break_point_count,
1197 int call_count) {
1198 break_point_hit_count = 0;
1199 for (int i = 0; i < call_count; i++) {
1200 f->Call(recv, 0, NULL);
1201 CHECK_EQ((i + 1) * break_point_count, break_point_hit_count);
1202 }
1203}
1204
1205// Test GC during break point processing.
1206TEST(GCDuringBreakPointProcessing) {
1207 break_point_hit_count = 0;
1208 v8::HandleScope scope;
1209 DebugLocalContext env;
1210
1211 v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage,
1212 v8::Undefined());
1213 v8::Local<v8::Function> foo;
1214
1215 // Test IC store break point with garbage collection.
1216 foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1217 SetBreakPoint(foo, 0);
1218 CallWithBreakPoints(env->Global(), foo, 1, 10);
1219
1220 // Test IC load break point with garbage collection.
1221 foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1222 SetBreakPoint(foo, 0);
1223 CallWithBreakPoints(env->Global(), foo, 1, 10);
1224
1225 // Test IC call break point with garbage collection.
1226 foo = CompileFunction(&env, "function bar(){};function foo(){bar();}", "foo");
1227 SetBreakPoint(foo, 0);
1228 CallWithBreakPoints(env->Global(), foo, 1, 10);
1229
1230 // Test return break point with garbage collection.
1231 foo = CompileFunction(&env, "function foo(){}", "foo");
1232 SetBreakPoint(foo, 0);
1233 CallWithBreakPoints(env->Global(), foo, 1, 25);
1234
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001235 // Test debug break slot break point with garbage collection.
1236 foo = CompileFunction(&env, "function foo(){var a;}", "foo");
1237 SetBreakPoint(foo, 0);
1238 CallWithBreakPoints(env->Global(), foo, 1, 25);
1239
Steve Blocka7e24c12009-10-30 11:49:00 +00001240 v8::Debug::SetDebugEventListener(NULL);
1241 CheckDebuggerUnloaded();
1242}
1243
1244
1245// Call the function three times with different garbage collections in between
1246// and make sure that the break point survives.
Ben Murdochbb769b22010-08-11 14:56:33 +01001247static void CallAndGC(v8::Local<v8::Object> recv,
1248 v8::Local<v8::Function> f,
1249 bool force_compaction) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001250 break_point_hit_count = 0;
1251
1252 for (int i = 0; i < 3; i++) {
1253 // Call function.
1254 f->Call(recv, 0, NULL);
1255 CHECK_EQ(1 + i * 3, break_point_hit_count);
1256
1257 // Scavenge and call function.
1258 Heap::CollectGarbage(0, v8::internal::NEW_SPACE);
1259 f->Call(recv, 0, NULL);
1260 CHECK_EQ(2 + i * 3, break_point_hit_count);
1261
1262 // Mark sweep (and perhaps compact) and call function.
Ben Murdochbb769b22010-08-11 14:56:33 +01001263 Heap::CollectAllGarbage(force_compaction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001264 f->Call(recv, 0, NULL);
1265 CHECK_EQ(3 + i * 3, break_point_hit_count);
1266 }
1267}
1268
1269
Ben Murdochbb769b22010-08-11 14:56:33 +01001270static void TestBreakPointSurviveGC(bool force_compaction) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001271 break_point_hit_count = 0;
1272 v8::HandleScope scope;
1273 DebugLocalContext env;
1274
1275 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1276 v8::Undefined());
1277 v8::Local<v8::Function> foo;
1278
1279 // Test IC store break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001280 {
1281 v8::Local<v8::Function> bar =
1282 CompileFunction(&env, "function foo(){}", "foo");
1283 foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1284 SetBreakPoint(foo, 0);
1285 }
1286 CallAndGC(env->Global(), foo, force_compaction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001287
1288 // Test IC load break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001289 {
1290 v8::Local<v8::Function> bar =
1291 CompileFunction(&env, "function foo(){}", "foo");
1292 foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1293 SetBreakPoint(foo, 0);
1294 }
1295 CallAndGC(env->Global(), foo, force_compaction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001296
1297 // Test IC call break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001298 {
1299 v8::Local<v8::Function> bar =
1300 CompileFunction(&env, "function foo(){}", "foo");
1301 foo = CompileFunction(&env,
1302 "function bar(){};function foo(){bar();}",
1303 "foo");
1304 SetBreakPoint(foo, 0);
1305 }
1306 CallAndGC(env->Global(), foo, force_compaction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001307
1308 // Test return break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001309 {
1310 v8::Local<v8::Function> bar =
1311 CompileFunction(&env, "function foo(){}", "foo");
1312 foo = CompileFunction(&env, "function foo(){}", "foo");
1313 SetBreakPoint(foo, 0);
1314 }
1315 CallAndGC(env->Global(), foo, force_compaction);
1316
1317 // Test non IC break point with garbage collection.
1318 {
1319 v8::Local<v8::Function> bar =
1320 CompileFunction(&env, "function foo(){}", "foo");
1321 foo = CompileFunction(&env, "function foo(){var bar=0;}", "foo");
1322 SetBreakPoint(foo, 0);
1323 }
1324 CallAndGC(env->Global(), foo, force_compaction);
1325
Steve Blocka7e24c12009-10-30 11:49:00 +00001326
1327 v8::Debug::SetDebugEventListener(NULL);
1328 CheckDebuggerUnloaded();
1329}
1330
1331
Ben Murdochbb769b22010-08-11 14:56:33 +01001332// Test that a break point can be set at a return store location.
1333TEST(BreakPointSurviveGC) {
1334 TestBreakPointSurviveGC(false);
1335 TestBreakPointSurviveGC(true);
1336}
1337
1338
Steve Blocka7e24c12009-10-30 11:49:00 +00001339// Test that break points can be set using the global Debug object.
1340TEST(BreakPointThroughJavaScript) {
1341 break_point_hit_count = 0;
1342 v8::HandleScope scope;
1343 DebugLocalContext env;
1344 env.ExposeDebug();
1345
1346 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1347 v8::Undefined());
1348 v8::Script::Compile(v8::String::New("function bar(){}"))->Run();
1349 v8::Script::Compile(v8::String::New("function foo(){bar();bar();}"))->Run();
1350 // 012345678901234567890
1351 // 1 2
1352 // Break points are set at position 3 and 9
1353 v8::Local<v8::Script> foo = v8::Script::Compile(v8::String::New("foo()"));
1354
1355 // Run without breakpoints.
1356 foo->Run();
1357 CHECK_EQ(0, break_point_hit_count);
1358
1359 // Run with one breakpoint
1360 int bp1 = SetBreakPointFromJS("foo", 0, 3);
1361 foo->Run();
1362 CHECK_EQ(1, break_point_hit_count);
1363 foo->Run();
1364 CHECK_EQ(2, break_point_hit_count);
1365
1366 // Run with two breakpoints
1367 int bp2 = SetBreakPointFromJS("foo", 0, 9);
1368 foo->Run();
1369 CHECK_EQ(4, break_point_hit_count);
1370 foo->Run();
1371 CHECK_EQ(6, break_point_hit_count);
1372
1373 // Run with one breakpoint
1374 ClearBreakPointFromJS(bp2);
1375 foo->Run();
1376 CHECK_EQ(7, break_point_hit_count);
1377 foo->Run();
1378 CHECK_EQ(8, break_point_hit_count);
1379
1380 // Run without breakpoints.
1381 ClearBreakPointFromJS(bp1);
1382 foo->Run();
1383 CHECK_EQ(8, break_point_hit_count);
1384
1385 v8::Debug::SetDebugEventListener(NULL);
1386 CheckDebuggerUnloaded();
1387
1388 // Make sure that the break point numbers are consecutive.
1389 CHECK_EQ(1, bp1);
1390 CHECK_EQ(2, bp2);
1391}
1392
1393
1394// Test that break points on scripts identified by name can be set using the
1395// global Debug object.
1396TEST(ScriptBreakPointByNameThroughJavaScript) {
1397 break_point_hit_count = 0;
1398 v8::HandleScope scope;
1399 DebugLocalContext env;
1400 env.ExposeDebug();
1401
1402 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1403 v8::Undefined());
1404
1405 v8::Local<v8::String> script = v8::String::New(
1406 "function f() {\n"
1407 " function h() {\n"
1408 " a = 0; // line 2\n"
1409 " }\n"
1410 " b = 1; // line 4\n"
1411 " return h();\n"
1412 "}\n"
1413 "\n"
1414 "function g() {\n"
1415 " function h() {\n"
1416 " a = 0;\n"
1417 " }\n"
1418 " b = 2; // line 12\n"
1419 " h();\n"
1420 " b = 3; // line 14\n"
1421 " f(); // line 15\n"
1422 "}");
1423
1424 // Compile the script and get the two functions.
1425 v8::ScriptOrigin origin =
1426 v8::ScriptOrigin(v8::String::New("test"));
1427 v8::Script::Compile(script, &origin)->Run();
1428 v8::Local<v8::Function> f =
1429 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1430 v8::Local<v8::Function> g =
1431 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
1432
1433 // Call f and g without break points.
1434 break_point_hit_count = 0;
1435 f->Call(env->Global(), 0, NULL);
1436 CHECK_EQ(0, break_point_hit_count);
1437 g->Call(env->Global(), 0, NULL);
1438 CHECK_EQ(0, break_point_hit_count);
1439
1440 // Call f and g with break point on line 12.
1441 int sbp1 = SetScriptBreakPointByNameFromJS("test", 12, 0);
1442 break_point_hit_count = 0;
1443 f->Call(env->Global(), 0, NULL);
1444 CHECK_EQ(0, break_point_hit_count);
1445 g->Call(env->Global(), 0, NULL);
1446 CHECK_EQ(1, break_point_hit_count);
1447
1448 // Remove the break point again.
1449 break_point_hit_count = 0;
1450 ClearBreakPointFromJS(sbp1);
1451 f->Call(env->Global(), 0, NULL);
1452 CHECK_EQ(0, break_point_hit_count);
1453 g->Call(env->Global(), 0, NULL);
1454 CHECK_EQ(0, break_point_hit_count);
1455
1456 // Call f and g with break point on line 2.
1457 int sbp2 = SetScriptBreakPointByNameFromJS("test", 2, 0);
1458 break_point_hit_count = 0;
1459 f->Call(env->Global(), 0, NULL);
1460 CHECK_EQ(1, break_point_hit_count);
1461 g->Call(env->Global(), 0, NULL);
1462 CHECK_EQ(2, break_point_hit_count);
1463
1464 // Call f and g with break point on line 2, 4, 12, 14 and 15.
1465 int sbp3 = SetScriptBreakPointByNameFromJS("test", 4, 0);
1466 int sbp4 = SetScriptBreakPointByNameFromJS("test", 12, 0);
1467 int sbp5 = SetScriptBreakPointByNameFromJS("test", 14, 0);
1468 int sbp6 = SetScriptBreakPointByNameFromJS("test", 15, 0);
1469 break_point_hit_count = 0;
1470 f->Call(env->Global(), 0, NULL);
1471 CHECK_EQ(2, break_point_hit_count);
1472 g->Call(env->Global(), 0, NULL);
1473 CHECK_EQ(7, break_point_hit_count);
1474
1475 // Remove all the break points again.
1476 break_point_hit_count = 0;
1477 ClearBreakPointFromJS(sbp2);
1478 ClearBreakPointFromJS(sbp3);
1479 ClearBreakPointFromJS(sbp4);
1480 ClearBreakPointFromJS(sbp5);
1481 ClearBreakPointFromJS(sbp6);
1482 f->Call(env->Global(), 0, NULL);
1483 CHECK_EQ(0, break_point_hit_count);
1484 g->Call(env->Global(), 0, NULL);
1485 CHECK_EQ(0, break_point_hit_count);
1486
1487 v8::Debug::SetDebugEventListener(NULL);
1488 CheckDebuggerUnloaded();
1489
1490 // Make sure that the break point numbers are consecutive.
1491 CHECK_EQ(1, sbp1);
1492 CHECK_EQ(2, sbp2);
1493 CHECK_EQ(3, sbp3);
1494 CHECK_EQ(4, sbp4);
1495 CHECK_EQ(5, sbp5);
1496 CHECK_EQ(6, sbp6);
1497}
1498
1499
1500TEST(ScriptBreakPointByIdThroughJavaScript) {
1501 break_point_hit_count = 0;
1502 v8::HandleScope scope;
1503 DebugLocalContext env;
1504 env.ExposeDebug();
1505
1506 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1507 v8::Undefined());
1508
1509 v8::Local<v8::String> source = v8::String::New(
1510 "function f() {\n"
1511 " function h() {\n"
1512 " a = 0; // line 2\n"
1513 " }\n"
1514 " b = 1; // line 4\n"
1515 " return h();\n"
1516 "}\n"
1517 "\n"
1518 "function g() {\n"
1519 " function h() {\n"
1520 " a = 0;\n"
1521 " }\n"
1522 " b = 2; // line 12\n"
1523 " h();\n"
1524 " b = 3; // line 14\n"
1525 " f(); // line 15\n"
1526 "}");
1527
1528 // Compile the script and get the two functions.
1529 v8::ScriptOrigin origin =
1530 v8::ScriptOrigin(v8::String::New("test"));
1531 v8::Local<v8::Script> script = v8::Script::Compile(source, &origin);
1532 script->Run();
1533 v8::Local<v8::Function> f =
1534 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1535 v8::Local<v8::Function> g =
1536 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
1537
1538 // Get the script id knowing that internally it is a 32 integer.
1539 uint32_t script_id = script->Id()->Uint32Value();
1540
1541 // Call f and g without break points.
1542 break_point_hit_count = 0;
1543 f->Call(env->Global(), 0, NULL);
1544 CHECK_EQ(0, break_point_hit_count);
1545 g->Call(env->Global(), 0, NULL);
1546 CHECK_EQ(0, break_point_hit_count);
1547
1548 // Call f and g with break point on line 12.
1549 int sbp1 = SetScriptBreakPointByIdFromJS(script_id, 12, 0);
1550 break_point_hit_count = 0;
1551 f->Call(env->Global(), 0, NULL);
1552 CHECK_EQ(0, break_point_hit_count);
1553 g->Call(env->Global(), 0, NULL);
1554 CHECK_EQ(1, break_point_hit_count);
1555
1556 // Remove the break point again.
1557 break_point_hit_count = 0;
1558 ClearBreakPointFromJS(sbp1);
1559 f->Call(env->Global(), 0, NULL);
1560 CHECK_EQ(0, break_point_hit_count);
1561 g->Call(env->Global(), 0, NULL);
1562 CHECK_EQ(0, break_point_hit_count);
1563
1564 // Call f and g with break point on line 2.
1565 int sbp2 = SetScriptBreakPointByIdFromJS(script_id, 2, 0);
1566 break_point_hit_count = 0;
1567 f->Call(env->Global(), 0, NULL);
1568 CHECK_EQ(1, break_point_hit_count);
1569 g->Call(env->Global(), 0, NULL);
1570 CHECK_EQ(2, break_point_hit_count);
1571
1572 // Call f and g with break point on line 2, 4, 12, 14 and 15.
1573 int sbp3 = SetScriptBreakPointByIdFromJS(script_id, 4, 0);
1574 int sbp4 = SetScriptBreakPointByIdFromJS(script_id, 12, 0);
1575 int sbp5 = SetScriptBreakPointByIdFromJS(script_id, 14, 0);
1576 int sbp6 = SetScriptBreakPointByIdFromJS(script_id, 15, 0);
1577 break_point_hit_count = 0;
1578 f->Call(env->Global(), 0, NULL);
1579 CHECK_EQ(2, break_point_hit_count);
1580 g->Call(env->Global(), 0, NULL);
1581 CHECK_EQ(7, break_point_hit_count);
1582
1583 // Remove all the break points again.
1584 break_point_hit_count = 0;
1585 ClearBreakPointFromJS(sbp2);
1586 ClearBreakPointFromJS(sbp3);
1587 ClearBreakPointFromJS(sbp4);
1588 ClearBreakPointFromJS(sbp5);
1589 ClearBreakPointFromJS(sbp6);
1590 f->Call(env->Global(), 0, NULL);
1591 CHECK_EQ(0, break_point_hit_count);
1592 g->Call(env->Global(), 0, NULL);
1593 CHECK_EQ(0, break_point_hit_count);
1594
1595 v8::Debug::SetDebugEventListener(NULL);
1596 CheckDebuggerUnloaded();
1597
1598 // Make sure that the break point numbers are consecutive.
1599 CHECK_EQ(1, sbp1);
1600 CHECK_EQ(2, sbp2);
1601 CHECK_EQ(3, sbp3);
1602 CHECK_EQ(4, sbp4);
1603 CHECK_EQ(5, sbp5);
1604 CHECK_EQ(6, sbp6);
1605}
1606
1607
1608// Test conditional script break points.
1609TEST(EnableDisableScriptBreakPoint) {
1610 break_point_hit_count = 0;
1611 v8::HandleScope scope;
1612 DebugLocalContext env;
1613 env.ExposeDebug();
1614
1615 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1616 v8::Undefined());
1617
1618 v8::Local<v8::String> script = v8::String::New(
1619 "function f() {\n"
1620 " a = 0; // line 1\n"
1621 "};");
1622
1623 // Compile the script and get function f.
1624 v8::ScriptOrigin origin =
1625 v8::ScriptOrigin(v8::String::New("test"));
1626 v8::Script::Compile(script, &origin)->Run();
1627 v8::Local<v8::Function> f =
1628 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1629
1630 // Set script break point on line 1 (in function f).
1631 int sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
1632
1633 // Call f while enabeling and disabling the script break point.
1634 break_point_hit_count = 0;
1635 f->Call(env->Global(), 0, NULL);
1636 CHECK_EQ(1, break_point_hit_count);
1637
1638 DisableScriptBreakPointFromJS(sbp);
1639 f->Call(env->Global(), 0, NULL);
1640 CHECK_EQ(1, break_point_hit_count);
1641
1642 EnableScriptBreakPointFromJS(sbp);
1643 f->Call(env->Global(), 0, NULL);
1644 CHECK_EQ(2, break_point_hit_count);
1645
1646 DisableScriptBreakPointFromJS(sbp);
1647 f->Call(env->Global(), 0, NULL);
1648 CHECK_EQ(2, break_point_hit_count);
1649
1650 // Reload the script and get f again checking that the disabeling survives.
1651 v8::Script::Compile(script, &origin)->Run();
1652 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1653 f->Call(env->Global(), 0, NULL);
1654 CHECK_EQ(2, break_point_hit_count);
1655
1656 EnableScriptBreakPointFromJS(sbp);
1657 f->Call(env->Global(), 0, NULL);
1658 CHECK_EQ(3, break_point_hit_count);
1659
1660 v8::Debug::SetDebugEventListener(NULL);
1661 CheckDebuggerUnloaded();
1662}
1663
1664
1665// Test conditional script break points.
1666TEST(ConditionalScriptBreakPoint) {
1667 break_point_hit_count = 0;
1668 v8::HandleScope scope;
1669 DebugLocalContext env;
1670 env.ExposeDebug();
1671
1672 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1673 v8::Undefined());
1674
1675 v8::Local<v8::String> script = v8::String::New(
1676 "count = 0;\n"
1677 "function f() {\n"
1678 " g(count++); // line 2\n"
1679 "};\n"
1680 "function g(x) {\n"
1681 " var a=x; // line 5\n"
1682 "};");
1683
1684 // Compile the script and get function f.
1685 v8::ScriptOrigin origin =
1686 v8::ScriptOrigin(v8::String::New("test"));
1687 v8::Script::Compile(script, &origin)->Run();
1688 v8::Local<v8::Function> f =
1689 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1690
1691 // Set script break point on line 5 (in function g).
1692 int sbp1 = SetScriptBreakPointByNameFromJS("test", 5, 0);
1693
1694 // Call f with different conditions on the script break point.
1695 break_point_hit_count = 0;
1696 ChangeScriptBreakPointConditionFromJS(sbp1, "false");
1697 f->Call(env->Global(), 0, NULL);
1698 CHECK_EQ(0, break_point_hit_count);
1699
1700 ChangeScriptBreakPointConditionFromJS(sbp1, "true");
1701 break_point_hit_count = 0;
1702 f->Call(env->Global(), 0, NULL);
1703 CHECK_EQ(1, break_point_hit_count);
1704
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001705 ChangeScriptBreakPointConditionFromJS(sbp1, "x % 2 == 0");
Steve Blocka7e24c12009-10-30 11:49:00 +00001706 break_point_hit_count = 0;
1707 for (int i = 0; i < 10; i++) {
1708 f->Call(env->Global(), 0, NULL);
1709 }
1710 CHECK_EQ(5, break_point_hit_count);
1711
1712 // Reload the script and get f again checking that the condition survives.
1713 v8::Script::Compile(script, &origin)->Run();
1714 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1715
1716 break_point_hit_count = 0;
1717 for (int i = 0; i < 10; i++) {
1718 f->Call(env->Global(), 0, NULL);
1719 }
1720 CHECK_EQ(5, break_point_hit_count);
1721
1722 v8::Debug::SetDebugEventListener(NULL);
1723 CheckDebuggerUnloaded();
1724}
1725
1726
1727// Test ignore count on script break points.
1728TEST(ScriptBreakPointIgnoreCount) {
1729 break_point_hit_count = 0;
1730 v8::HandleScope scope;
1731 DebugLocalContext env;
1732 env.ExposeDebug();
1733
1734 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1735 v8::Undefined());
1736
1737 v8::Local<v8::String> script = v8::String::New(
1738 "function f() {\n"
1739 " a = 0; // line 1\n"
1740 "};");
1741
1742 // Compile the script and get function f.
1743 v8::ScriptOrigin origin =
1744 v8::ScriptOrigin(v8::String::New("test"));
1745 v8::Script::Compile(script, &origin)->Run();
1746 v8::Local<v8::Function> f =
1747 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1748
1749 // Set script break point on line 1 (in function f).
1750 int sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
1751
1752 // Call f with different ignores on the script break point.
1753 break_point_hit_count = 0;
1754 ChangeScriptBreakPointIgnoreCountFromJS(sbp, 1);
1755 f->Call(env->Global(), 0, NULL);
1756 CHECK_EQ(0, break_point_hit_count);
1757 f->Call(env->Global(), 0, NULL);
1758 CHECK_EQ(1, break_point_hit_count);
1759
1760 ChangeScriptBreakPointIgnoreCountFromJS(sbp, 5);
1761 break_point_hit_count = 0;
1762 for (int i = 0; i < 10; i++) {
1763 f->Call(env->Global(), 0, NULL);
1764 }
1765 CHECK_EQ(5, break_point_hit_count);
1766
1767 // Reload the script and get f again checking that the ignore survives.
1768 v8::Script::Compile(script, &origin)->Run();
1769 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1770
1771 break_point_hit_count = 0;
1772 for (int i = 0; i < 10; i++) {
1773 f->Call(env->Global(), 0, NULL);
1774 }
1775 CHECK_EQ(5, break_point_hit_count);
1776
1777 v8::Debug::SetDebugEventListener(NULL);
1778 CheckDebuggerUnloaded();
1779}
1780
1781
1782// Test that script break points survive when a script is reloaded.
1783TEST(ScriptBreakPointReload) {
1784 break_point_hit_count = 0;
1785 v8::HandleScope scope;
1786 DebugLocalContext env;
1787 env.ExposeDebug();
1788
1789 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1790 v8::Undefined());
1791
1792 v8::Local<v8::Function> f;
1793 v8::Local<v8::String> script = v8::String::New(
1794 "function f() {\n"
1795 " function h() {\n"
1796 " a = 0; // line 2\n"
1797 " }\n"
1798 " b = 1; // line 4\n"
1799 " return h();\n"
1800 "}");
1801
1802 v8::ScriptOrigin origin_1 = v8::ScriptOrigin(v8::String::New("1"));
1803 v8::ScriptOrigin origin_2 = v8::ScriptOrigin(v8::String::New("2"));
1804
1805 // Set a script break point before the script is loaded.
1806 SetScriptBreakPointByNameFromJS("1", 2, 0);
1807
1808 // Compile the script and get the function.
1809 v8::Script::Compile(script, &origin_1)->Run();
1810 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1811
1812 // Call f and check that the script break point is active.
1813 break_point_hit_count = 0;
1814 f->Call(env->Global(), 0, NULL);
1815 CHECK_EQ(1, break_point_hit_count);
1816
1817 // Compile the script again with a different script data and get the
1818 // function.
1819 v8::Script::Compile(script, &origin_2)->Run();
1820 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1821
1822 // Call f and check that no break points are set.
1823 break_point_hit_count = 0;
1824 f->Call(env->Global(), 0, NULL);
1825 CHECK_EQ(0, break_point_hit_count);
1826
1827 // Compile the script again and get the function.
1828 v8::Script::Compile(script, &origin_1)->Run();
1829 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1830
1831 // Call f and check that the script break point is active.
1832 break_point_hit_count = 0;
1833 f->Call(env->Global(), 0, NULL);
1834 CHECK_EQ(1, break_point_hit_count);
1835
1836 v8::Debug::SetDebugEventListener(NULL);
1837 CheckDebuggerUnloaded();
1838}
1839
1840
1841// Test when several scripts has the same script data
1842TEST(ScriptBreakPointMultiple) {
1843 break_point_hit_count = 0;
1844 v8::HandleScope scope;
1845 DebugLocalContext env;
1846 env.ExposeDebug();
1847
1848 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1849 v8::Undefined());
1850
1851 v8::Local<v8::Function> f;
1852 v8::Local<v8::String> script_f = v8::String::New(
1853 "function f() {\n"
1854 " a = 0; // line 1\n"
1855 "}");
1856
1857 v8::Local<v8::Function> g;
1858 v8::Local<v8::String> script_g = v8::String::New(
1859 "function g() {\n"
1860 " b = 0; // line 1\n"
1861 "}");
1862
1863 v8::ScriptOrigin origin =
1864 v8::ScriptOrigin(v8::String::New("test"));
1865
1866 // Set a script break point before the scripts are loaded.
1867 int sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
1868
1869 // Compile the scripts with same script data and get the functions.
1870 v8::Script::Compile(script_f, &origin)->Run();
1871 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1872 v8::Script::Compile(script_g, &origin)->Run();
1873 g = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
1874
1875 // Call f and g and check that the script break point is active.
1876 break_point_hit_count = 0;
1877 f->Call(env->Global(), 0, NULL);
1878 CHECK_EQ(1, break_point_hit_count);
1879 g->Call(env->Global(), 0, NULL);
1880 CHECK_EQ(2, break_point_hit_count);
1881
1882 // Clear the script break point.
1883 ClearBreakPointFromJS(sbp);
1884
1885 // Call f and g and check that the script break point is no longer active.
1886 break_point_hit_count = 0;
1887 f->Call(env->Global(), 0, NULL);
1888 CHECK_EQ(0, break_point_hit_count);
1889 g->Call(env->Global(), 0, NULL);
1890 CHECK_EQ(0, break_point_hit_count);
1891
1892 // Set script break point with the scripts loaded.
1893 sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
1894
1895 // Call f and g and check that the script break point is active.
1896 break_point_hit_count = 0;
1897 f->Call(env->Global(), 0, NULL);
1898 CHECK_EQ(1, break_point_hit_count);
1899 g->Call(env->Global(), 0, NULL);
1900 CHECK_EQ(2, break_point_hit_count);
1901
1902 v8::Debug::SetDebugEventListener(NULL);
1903 CheckDebuggerUnloaded();
1904}
1905
1906
1907// Test the script origin which has both name and line offset.
1908TEST(ScriptBreakPointLineOffset) {
1909 break_point_hit_count = 0;
1910 v8::HandleScope scope;
1911 DebugLocalContext env;
1912 env.ExposeDebug();
1913
1914 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1915 v8::Undefined());
1916
1917 v8::Local<v8::Function> f;
1918 v8::Local<v8::String> script = v8::String::New(
1919 "function f() {\n"
1920 " a = 0; // line 8 as this script has line offset 7\n"
1921 " b = 0; // line 9 as this script has line offset 7\n"
1922 "}");
1923
1924 // Create script origin both name and line offset.
1925 v8::ScriptOrigin origin(v8::String::New("test.html"),
1926 v8::Integer::New(7));
1927
1928 // Set two script break points before the script is loaded.
1929 int sbp1 = SetScriptBreakPointByNameFromJS("test.html", 8, 0);
1930 int sbp2 = SetScriptBreakPointByNameFromJS("test.html", 9, 0);
1931
1932 // Compile the script and get the function.
1933 v8::Script::Compile(script, &origin)->Run();
1934 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1935
1936 // Call f and check that the script break point is active.
1937 break_point_hit_count = 0;
1938 f->Call(env->Global(), 0, NULL);
1939 CHECK_EQ(2, break_point_hit_count);
1940
1941 // Clear the script break points.
1942 ClearBreakPointFromJS(sbp1);
1943 ClearBreakPointFromJS(sbp2);
1944
1945 // Call f and check that no script break points are active.
1946 break_point_hit_count = 0;
1947 f->Call(env->Global(), 0, NULL);
1948 CHECK_EQ(0, break_point_hit_count);
1949
1950 // Set a script break point with the script loaded.
1951 sbp1 = SetScriptBreakPointByNameFromJS("test.html", 9, 0);
1952
1953 // Call f and check that the script break point is active.
1954 break_point_hit_count = 0;
1955 f->Call(env->Global(), 0, NULL);
1956 CHECK_EQ(1, break_point_hit_count);
1957
1958 v8::Debug::SetDebugEventListener(NULL);
1959 CheckDebuggerUnloaded();
1960}
1961
1962
1963// Test script break points set on lines.
1964TEST(ScriptBreakPointLine) {
1965 v8::HandleScope scope;
1966 DebugLocalContext env;
1967 env.ExposeDebug();
1968
1969 // Create a function for checking the function when hitting a break point.
1970 frame_function_name = CompileFunction(&env,
1971 frame_function_name_source,
1972 "frame_function_name");
1973
1974 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1975 v8::Undefined());
1976
1977 v8::Local<v8::Function> f;
1978 v8::Local<v8::Function> g;
1979 v8::Local<v8::String> script = v8::String::New(
1980 "a = 0 // line 0\n"
1981 "function f() {\n"
1982 " a = 1; // line 2\n"
1983 "}\n"
1984 " a = 2; // line 4\n"
1985 " /* xx */ function g() { // line 5\n"
1986 " function h() { // line 6\n"
1987 " a = 3; // line 7\n"
1988 " }\n"
1989 " h(); // line 9\n"
1990 " a = 4; // line 10\n"
1991 " }\n"
1992 " a=5; // line 12");
1993
1994 // Set a couple script break point before the script is loaded.
1995 int sbp1 = SetScriptBreakPointByNameFromJS("test.html", 0, -1);
1996 int sbp2 = SetScriptBreakPointByNameFromJS("test.html", 1, -1);
1997 int sbp3 = SetScriptBreakPointByNameFromJS("test.html", 5, -1);
1998
1999 // Compile the script and get the function.
2000 break_point_hit_count = 0;
2001 v8::ScriptOrigin origin(v8::String::New("test.html"), v8::Integer::New(0));
2002 v8::Script::Compile(script, &origin)->Run();
2003 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2004 g = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
2005
2006 // Chesk that a break point was hit when the script was run.
2007 CHECK_EQ(1, break_point_hit_count);
Steve Blockd0582a62009-12-15 09:54:21 +00002008 CHECK_EQ(0, StrLength(last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00002009
2010 // Call f and check that the script break point.
2011 f->Call(env->Global(), 0, NULL);
2012 CHECK_EQ(2, break_point_hit_count);
2013 CHECK_EQ("f", last_function_hit);
2014
2015 // Call g and check that the script break point.
2016 g->Call(env->Global(), 0, NULL);
2017 CHECK_EQ(3, break_point_hit_count);
2018 CHECK_EQ("g", last_function_hit);
2019
2020 // Clear the script break point on g and set one on h.
2021 ClearBreakPointFromJS(sbp3);
2022 int sbp4 = SetScriptBreakPointByNameFromJS("test.html", 6, -1);
2023
2024 // Call g and check that the script break point in h is hit.
2025 g->Call(env->Global(), 0, NULL);
2026 CHECK_EQ(4, break_point_hit_count);
2027 CHECK_EQ("h", last_function_hit);
2028
2029 // Clear break points in f and h. Set a new one in the script between
2030 // functions f and g and test that there is no break points in f and g any
2031 // more.
2032 ClearBreakPointFromJS(sbp2);
2033 ClearBreakPointFromJS(sbp4);
2034 int sbp5 = SetScriptBreakPointByNameFromJS("test.html", 4, -1);
2035 break_point_hit_count = 0;
2036 f->Call(env->Global(), 0, NULL);
2037 g->Call(env->Global(), 0, NULL);
2038 CHECK_EQ(0, break_point_hit_count);
2039
2040 // Reload the script which should hit two break points.
2041 break_point_hit_count = 0;
2042 v8::Script::Compile(script, &origin)->Run();
2043 CHECK_EQ(2, break_point_hit_count);
Steve Blockd0582a62009-12-15 09:54:21 +00002044 CHECK_EQ(0, StrLength(last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00002045
2046 // Set a break point in the code after the last function decleration.
2047 int sbp6 = SetScriptBreakPointByNameFromJS("test.html", 12, -1);
2048
2049 // Reload the script which should hit three break points.
2050 break_point_hit_count = 0;
2051 v8::Script::Compile(script, &origin)->Run();
2052 CHECK_EQ(3, break_point_hit_count);
Steve Blockd0582a62009-12-15 09:54:21 +00002053 CHECK_EQ(0, StrLength(last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00002054
2055 // Clear the last break points, and reload the script which should not hit any
2056 // break points.
2057 ClearBreakPointFromJS(sbp1);
2058 ClearBreakPointFromJS(sbp5);
2059 ClearBreakPointFromJS(sbp6);
2060 break_point_hit_count = 0;
2061 v8::Script::Compile(script, &origin)->Run();
2062 CHECK_EQ(0, break_point_hit_count);
2063
2064 v8::Debug::SetDebugEventListener(NULL);
2065 CheckDebuggerUnloaded();
2066}
2067
2068
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002069// Test top level script break points set on lines.
2070TEST(ScriptBreakPointLineTopLevel) {
2071 v8::HandleScope scope;
2072 DebugLocalContext env;
2073 env.ExposeDebug();
2074
2075 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2076 v8::Undefined());
2077
2078 v8::Local<v8::String> script = v8::String::New(
2079 "function f() {\n"
2080 " a = 1; // line 1\n"
2081 "}\n"
2082 "a = 2; // line 3\n");
2083 v8::Local<v8::Function> f;
2084 {
2085 v8::HandleScope scope;
2086 v8::Script::Compile(script, v8::String::New("test.html"))->Run();
2087 }
2088 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2089
2090 Heap::CollectAllGarbage(false);
2091
2092 SetScriptBreakPointByNameFromJS("test.html", 3, -1);
2093
2094 // Call f and check that there was no break points.
2095 break_point_hit_count = 0;
2096 f->Call(env->Global(), 0, NULL);
2097 CHECK_EQ(0, break_point_hit_count);
2098
2099 // Recompile and run script and check that break point was hit.
2100 break_point_hit_count = 0;
2101 v8::Script::Compile(script, v8::String::New("test.html"))->Run();
2102 CHECK_EQ(1, break_point_hit_count);
2103
2104 // Call f and check that there are still no break points.
2105 break_point_hit_count = 0;
2106 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2107 CHECK_EQ(0, break_point_hit_count);
2108
2109 v8::Debug::SetDebugEventListener(NULL);
2110 CheckDebuggerUnloaded();
2111}
2112
2113
Steve Block8defd9f2010-07-08 12:39:36 +01002114// Test that it is possible to add and remove break points in a top level
2115// function which has no references but has not been collected yet.
2116TEST(ScriptBreakPointTopLevelCrash) {
2117 v8::HandleScope scope;
2118 DebugLocalContext env;
2119 env.ExposeDebug();
2120
2121 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2122 v8::Undefined());
2123
2124 v8::Local<v8::String> script_source = v8::String::New(
2125 "function f() {\n"
2126 " return 0;\n"
2127 "}\n"
2128 "f()");
2129
2130 int sbp1 = SetScriptBreakPointByNameFromJS("test.html", 3, -1);
2131 {
2132 v8::HandleScope scope;
2133 break_point_hit_count = 0;
2134 v8::Script::Compile(script_source, v8::String::New("test.html"))->Run();
2135 CHECK_EQ(1, break_point_hit_count);
2136 }
2137
2138 int sbp2 = SetScriptBreakPointByNameFromJS("test.html", 3, -1);
2139 ClearBreakPointFromJS(sbp1);
2140 ClearBreakPointFromJS(sbp2);
2141
2142 v8::Debug::SetDebugEventListener(NULL);
2143 CheckDebuggerUnloaded();
2144}
2145
2146
Steve Blocka7e24c12009-10-30 11:49:00 +00002147// Test that it is possible to remove the last break point for a function
2148// inside the break handling of that break point.
2149TEST(RemoveBreakPointInBreak) {
2150 v8::HandleScope scope;
2151 DebugLocalContext env;
2152
2153 v8::Local<v8::Function> foo =
2154 CompileFunction(&env, "function foo(){a=1;}", "foo");
2155 debug_event_remove_break_point = SetBreakPoint(foo, 0);
2156
2157 // Register the debug event listener pasing the function
2158 v8::Debug::SetDebugEventListener(DebugEventRemoveBreakPoint, foo);
2159
2160 break_point_hit_count = 0;
2161 foo->Call(env->Global(), 0, NULL);
2162 CHECK_EQ(1, break_point_hit_count);
2163
2164 break_point_hit_count = 0;
2165 foo->Call(env->Global(), 0, NULL);
2166 CHECK_EQ(0, break_point_hit_count);
2167
2168 v8::Debug::SetDebugEventListener(NULL);
2169 CheckDebuggerUnloaded();
2170}
2171
2172
2173// Test that the debugger statement causes a break.
2174TEST(DebuggerStatement) {
2175 break_point_hit_count = 0;
2176 v8::HandleScope scope;
2177 DebugLocalContext env;
2178 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2179 v8::Undefined());
2180 v8::Script::Compile(v8::String::New("function bar(){debugger}"))->Run();
2181 v8::Script::Compile(v8::String::New(
2182 "function foo(){debugger;debugger;}"))->Run();
2183 v8::Local<v8::Function> foo =
2184 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
2185 v8::Local<v8::Function> bar =
2186 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("bar")));
2187
2188 // Run function with debugger statement
2189 bar->Call(env->Global(), 0, NULL);
2190 CHECK_EQ(1, break_point_hit_count);
2191
2192 // Run function with two debugger statement
2193 foo->Call(env->Global(), 0, NULL);
2194 CHECK_EQ(3, break_point_hit_count);
2195
2196 v8::Debug::SetDebugEventListener(NULL);
2197 CheckDebuggerUnloaded();
2198}
2199
2200
Steve Block8defd9f2010-07-08 12:39:36 +01002201// Test setting a breakpoint on the debugger statement.
Leon Clarke4515c472010-02-03 11:58:03 +00002202TEST(DebuggerStatementBreakpoint) {
2203 break_point_hit_count = 0;
2204 v8::HandleScope scope;
2205 DebugLocalContext env;
2206 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2207 v8::Undefined());
2208 v8::Script::Compile(v8::String::New("function foo(){debugger;}"))->Run();
2209 v8::Local<v8::Function> foo =
2210 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
2211
2212 // The debugger statement triggers breakpint hit
2213 foo->Call(env->Global(), 0, NULL);
2214 CHECK_EQ(1, break_point_hit_count);
2215
2216 int bp = SetBreakPoint(foo, 0);
2217
2218 // Set breakpoint does not duplicate hits
2219 foo->Call(env->Global(), 0, NULL);
2220 CHECK_EQ(2, break_point_hit_count);
2221
2222 ClearBreakPoint(bp);
2223 v8::Debug::SetDebugEventListener(NULL);
2224 CheckDebuggerUnloaded();
2225}
2226
2227
Steve Blocka7e24c12009-10-30 11:49:00 +00002228// Thest that the evaluation of expressions when a break point is hit generates
2229// the correct results.
2230TEST(DebugEvaluate) {
2231 v8::HandleScope scope;
2232 DebugLocalContext env;
2233 env.ExposeDebug();
2234
2235 // Create a function for checking the evaluation when hitting a break point.
2236 evaluate_check_function = CompileFunction(&env,
2237 evaluate_check_source,
2238 "evaluate_check");
2239 // Register the debug event listener
2240 v8::Debug::SetDebugEventListener(DebugEventEvaluate);
2241
2242 // Different expected vaules of x and a when in a break point (u = undefined,
2243 // d = Hello, world!).
2244 struct EvaluateCheck checks_uu[] = {
2245 {"x", v8::Undefined()},
2246 {"a", v8::Undefined()},
2247 {NULL, v8::Handle<v8::Value>()}
2248 };
2249 struct EvaluateCheck checks_hu[] = {
2250 {"x", v8::String::New("Hello, world!")},
2251 {"a", v8::Undefined()},
2252 {NULL, v8::Handle<v8::Value>()}
2253 };
2254 struct EvaluateCheck checks_hh[] = {
2255 {"x", v8::String::New("Hello, world!")},
2256 {"a", v8::String::New("Hello, world!")},
2257 {NULL, v8::Handle<v8::Value>()}
2258 };
2259
2260 // Simple test function. The "y=0" is in the function foo to provide a break
2261 // location. For "y=0" the "y" is at position 15 in the barbar function
2262 // therefore setting breakpoint at position 15 will break at "y=0" and
2263 // setting it higher will break after.
2264 v8::Local<v8::Function> foo = CompileFunction(&env,
2265 "function foo(x) {"
2266 " var a;"
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002267 " y=0;" // To ensure break location 1.
Steve Blocka7e24c12009-10-30 11:49:00 +00002268 " a=x;"
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002269 " y=0;" // To ensure break location 2.
Steve Blocka7e24c12009-10-30 11:49:00 +00002270 "}",
2271 "foo");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002272 const int foo_break_position_1 = 15;
2273 const int foo_break_position_2 = 29;
Steve Blocka7e24c12009-10-30 11:49:00 +00002274
2275 // Arguments with one parameter "Hello, world!"
2276 v8::Handle<v8::Value> argv_foo[1] = { v8::String::New("Hello, world!") };
2277
2278 // Call foo with breakpoint set before a=x and undefined as parameter.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002279 int bp = SetBreakPoint(foo, foo_break_position_1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002280 checks = checks_uu;
2281 foo->Call(env->Global(), 0, NULL);
2282
2283 // Call foo with breakpoint set before a=x and parameter "Hello, world!".
2284 checks = checks_hu;
2285 foo->Call(env->Global(), 1, argv_foo);
2286
2287 // Call foo with breakpoint set after a=x and parameter "Hello, world!".
2288 ClearBreakPoint(bp);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002289 SetBreakPoint(foo, foo_break_position_2);
Steve Blocka7e24c12009-10-30 11:49:00 +00002290 checks = checks_hh;
2291 foo->Call(env->Global(), 1, argv_foo);
2292
2293 // Test function with an inner function. The "y=0" is in function barbar
2294 // to provide a break location. For "y=0" the "y" is at position 8 in the
2295 // barbar function therefore setting breakpoint at position 8 will break at
2296 // "y=0" and setting it higher will break after.
2297 v8::Local<v8::Function> bar = CompileFunction(&env,
2298 "y = 0;"
2299 "x = 'Goodbye, world!';"
2300 "function bar(x, b) {"
2301 " var a;"
2302 " function barbar() {"
2303 " y=0; /* To ensure break location.*/"
2304 " a=x;"
2305 " };"
2306 " debug.Debug.clearAllBreakPoints();"
2307 " barbar();"
2308 " y=0;a=x;"
2309 "}",
2310 "bar");
2311 const int barbar_break_position = 8;
2312
2313 // Call bar setting breakpoint before a=x in barbar and undefined as
2314 // parameter.
2315 checks = checks_uu;
2316 v8::Handle<v8::Value> argv_bar_1[2] = {
2317 v8::Undefined(),
2318 v8::Number::New(barbar_break_position)
2319 };
2320 bar->Call(env->Global(), 2, argv_bar_1);
2321
2322 // Call bar setting breakpoint before a=x in barbar and parameter
2323 // "Hello, world!".
2324 checks = checks_hu;
2325 v8::Handle<v8::Value> argv_bar_2[2] = {
2326 v8::String::New("Hello, world!"),
2327 v8::Number::New(barbar_break_position)
2328 };
2329 bar->Call(env->Global(), 2, argv_bar_2);
2330
2331 // Call bar setting breakpoint after a=x in barbar and parameter
2332 // "Hello, world!".
2333 checks = checks_hh;
2334 v8::Handle<v8::Value> argv_bar_3[2] = {
2335 v8::String::New("Hello, world!"),
2336 v8::Number::New(barbar_break_position + 1)
2337 };
2338 bar->Call(env->Global(), 2, argv_bar_3);
2339
2340 v8::Debug::SetDebugEventListener(NULL);
2341 CheckDebuggerUnloaded();
2342}
2343
Leon Clarkee46be812010-01-19 14:06:41 +00002344// Copies a C string to a 16-bit string. Does not check for buffer overflow.
2345// Does not use the V8 engine to convert strings, so it can be used
2346// in any thread. Returns the length of the string.
2347int AsciiToUtf16(const char* input_buffer, uint16_t* output_buffer) {
2348 int i;
2349 for (i = 0; input_buffer[i] != '\0'; ++i) {
2350 // ASCII does not use chars > 127, but be careful anyway.
2351 output_buffer[i] = static_cast<unsigned char>(input_buffer[i]);
2352 }
2353 output_buffer[i] = 0;
2354 return i;
2355}
2356
2357// Copies a 16-bit string to a C string by dropping the high byte of
2358// each character. Does not check for buffer overflow.
2359// Can be used in any thread. Requires string length as an input.
2360int Utf16ToAscii(const uint16_t* input_buffer, int length,
2361 char* output_buffer, int output_len = -1) {
2362 if (output_len >= 0) {
2363 if (length > output_len - 1) {
2364 length = output_len - 1;
2365 }
2366 }
2367
2368 for (int i = 0; i < length; ++i) {
2369 output_buffer[i] = static_cast<char>(input_buffer[i]);
2370 }
2371 output_buffer[length] = '\0';
2372 return length;
2373}
2374
2375
2376// We match parts of the message to get evaluate result int value.
2377bool GetEvaluateStringResult(char *message, char* buffer, int buffer_size) {
Leon Clarked91b9f72010-01-27 17:25:45 +00002378 if (strstr(message, "\"command\":\"evaluate\"") == NULL) {
2379 return false;
2380 }
2381 const char* prefix = "\"text\":\"";
2382 char* pos1 = strstr(message, prefix);
2383 if (pos1 == NULL) {
2384 return false;
2385 }
2386 pos1 += strlen(prefix);
2387 char* pos2 = strchr(pos1, '"');
2388 if (pos2 == NULL) {
Leon Clarkee46be812010-01-19 14:06:41 +00002389 return false;
2390 }
2391 Vector<char> buf(buffer, buffer_size);
Leon Clarked91b9f72010-01-27 17:25:45 +00002392 int len = static_cast<int>(pos2 - pos1);
2393 if (len > buffer_size - 1) {
2394 len = buffer_size - 1;
2395 }
2396 OS::StrNCpy(buf, pos1, len);
Leon Clarkee46be812010-01-19 14:06:41 +00002397 buffer[buffer_size - 1] = '\0';
2398 return true;
2399}
2400
2401
2402struct EvaluateResult {
2403 static const int kBufferSize = 20;
2404 char buffer[kBufferSize];
2405};
2406
2407struct DebugProcessDebugMessagesData {
2408 static const int kArraySize = 5;
2409 int counter;
2410 EvaluateResult results[kArraySize];
2411
2412 void reset() {
2413 counter = 0;
2414 }
2415 EvaluateResult* current() {
2416 return &results[counter % kArraySize];
2417 }
2418 void next() {
2419 counter++;
2420 }
2421};
2422
2423DebugProcessDebugMessagesData process_debug_messages_data;
2424
2425static void DebugProcessDebugMessagesHandler(
2426 const uint16_t* message,
2427 int length,
2428 v8::Debug::ClientData* client_data) {
2429
2430 const int kBufferSize = 100000;
2431 char print_buffer[kBufferSize];
2432 Utf16ToAscii(message, length, print_buffer, kBufferSize);
2433
2434 EvaluateResult* array_item = process_debug_messages_data.current();
2435
2436 bool res = GetEvaluateStringResult(print_buffer,
2437 array_item->buffer,
2438 EvaluateResult::kBufferSize);
2439 if (res) {
2440 process_debug_messages_data.next();
2441 }
2442}
2443
2444// Test that the evaluation of expressions works even from ProcessDebugMessages
2445// i.e. with empty stack.
2446TEST(DebugEvaluateWithoutStack) {
2447 v8::Debug::SetMessageHandler(DebugProcessDebugMessagesHandler);
2448
2449 v8::HandleScope scope;
2450 DebugLocalContext env;
2451
2452 const char* source =
2453 "var v1 = 'Pinguin';\n function getAnimal() { return 'Capy' + 'bara'; }";
2454
2455 v8::Script::Compile(v8::String::New(source))->Run();
2456
2457 v8::Debug::ProcessDebugMessages();
2458
2459 const int kBufferSize = 1000;
2460 uint16_t buffer[kBufferSize];
2461
2462 const char* command_111 = "{\"seq\":111,"
2463 "\"type\":\"request\","
2464 "\"command\":\"evaluate\","
2465 "\"arguments\":{"
2466 " \"global\":true,"
2467 " \"expression\":\"v1\",\"disable_break\":true"
2468 "}}";
2469
2470 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_111, buffer));
2471
2472 const char* command_112 = "{\"seq\":112,"
2473 "\"type\":\"request\","
2474 "\"command\":\"evaluate\","
2475 "\"arguments\":{"
2476 " \"global\":true,"
2477 " \"expression\":\"getAnimal()\",\"disable_break\":true"
2478 "}}";
2479
2480 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_112, buffer));
2481
2482 const char* command_113 = "{\"seq\":113,"
2483 "\"type\":\"request\","
2484 "\"command\":\"evaluate\","
2485 "\"arguments\":{"
2486 " \"global\":true,"
2487 " \"expression\":\"239 + 566\",\"disable_break\":true"
2488 "}}";
2489
2490 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_113, buffer));
2491
2492 v8::Debug::ProcessDebugMessages();
2493
2494 CHECK_EQ(3, process_debug_messages_data.counter);
2495
Leon Clarked91b9f72010-01-27 17:25:45 +00002496 CHECK_EQ(strcmp("Pinguin", process_debug_messages_data.results[0].buffer), 0);
2497 CHECK_EQ(strcmp("Capybara", process_debug_messages_data.results[1].buffer),
2498 0);
2499 CHECK_EQ(strcmp("805", process_debug_messages_data.results[2].buffer), 0);
Leon Clarkee46be812010-01-19 14:06:41 +00002500
2501 v8::Debug::SetMessageHandler(NULL);
2502 v8::Debug::SetDebugEventListener(NULL);
2503 CheckDebuggerUnloaded();
2504}
2505
Steve Blocka7e24c12009-10-30 11:49:00 +00002506
2507// Simple test of the stepping mechanism using only store ICs.
2508TEST(DebugStepLinear) {
2509 v8::HandleScope scope;
2510 DebugLocalContext env;
2511
2512 // Create a function for testing stepping.
2513 v8::Local<v8::Function> foo = CompileFunction(&env,
2514 "function foo(){a=1;b=1;c=1;}",
2515 "foo");
2516 SetBreakPoint(foo, 3);
2517
2518 // Register a debug event listener which steps and counts.
2519 v8::Debug::SetDebugEventListener(DebugEventStep);
2520
2521 step_action = StepIn;
2522 break_point_hit_count = 0;
2523 foo->Call(env->Global(), 0, NULL);
2524
2525 // With stepping all break locations are hit.
2526 CHECK_EQ(4, break_point_hit_count);
2527
2528 v8::Debug::SetDebugEventListener(NULL);
2529 CheckDebuggerUnloaded();
2530
2531 // Register a debug event listener which just counts.
2532 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2533
2534 SetBreakPoint(foo, 3);
2535 break_point_hit_count = 0;
2536 foo->Call(env->Global(), 0, NULL);
2537
2538 // Without stepping only active break points are hit.
2539 CHECK_EQ(1, break_point_hit_count);
2540
2541 v8::Debug::SetDebugEventListener(NULL);
2542 CheckDebuggerUnloaded();
2543}
2544
2545
2546// Test of the stepping mechanism for keyed load in a loop.
2547TEST(DebugStepKeyedLoadLoop) {
2548 v8::HandleScope scope;
2549 DebugLocalContext env;
2550
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002551 // Register a debug event listener which steps and counts.
2552 v8::Debug::SetDebugEventListener(DebugEventStep);
2553
Steve Blocka7e24c12009-10-30 11:49:00 +00002554 // Create a function for testing stepping of keyed load. The statement 'y=1'
2555 // is there to have more than one breakable statement in the loop, TODO(315).
2556 v8::Local<v8::Function> foo = CompileFunction(
2557 &env,
2558 "function foo(a) {\n"
2559 " var x;\n"
2560 " var len = a.length;\n"
2561 " for (var i = 0; i < len; i++) {\n"
2562 " y = 1;\n"
2563 " x = a[i];\n"
2564 " }\n"
2565 "}\n",
2566 "foo");
2567
2568 // Create array [0,1,2,3,4,5,6,7,8,9]
2569 v8::Local<v8::Array> a = v8::Array::New(10);
2570 for (int i = 0; i < 10; i++) {
2571 a->Set(v8::Number::New(i), v8::Number::New(i));
2572 }
2573
2574 // Call function without any break points to ensure inlining is in place.
2575 const int kArgc = 1;
2576 v8::Handle<v8::Value> args[kArgc] = { a };
2577 foo->Call(env->Global(), kArgc, args);
2578
Steve Blocka7e24c12009-10-30 11:49:00 +00002579 // Setup break point and step through the function.
2580 SetBreakPoint(foo, 3);
2581 step_action = StepNext;
2582 break_point_hit_count = 0;
2583 foo->Call(env->Global(), kArgc, args);
2584
2585 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002586 CHECK_EQ(33, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002587
2588 v8::Debug::SetDebugEventListener(NULL);
2589 CheckDebuggerUnloaded();
2590}
2591
2592
2593// Test of the stepping mechanism for keyed store in a loop.
2594TEST(DebugStepKeyedStoreLoop) {
2595 v8::HandleScope scope;
2596 DebugLocalContext env;
2597
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002598 // Register a debug event listener which steps and counts.
2599 v8::Debug::SetDebugEventListener(DebugEventStep);
2600
Steve Blocka7e24c12009-10-30 11:49:00 +00002601 // Create a function for testing stepping of keyed store. The statement 'y=1'
2602 // is there to have more than one breakable statement in the loop, TODO(315).
2603 v8::Local<v8::Function> foo = CompileFunction(
2604 &env,
2605 "function foo(a) {\n"
2606 " var len = a.length;\n"
2607 " for (var i = 0; i < len; i++) {\n"
2608 " y = 1;\n"
2609 " a[i] = 42;\n"
2610 " }\n"
2611 "}\n",
2612 "foo");
2613
2614 // Create array [0,1,2,3,4,5,6,7,8,9]
2615 v8::Local<v8::Array> a = v8::Array::New(10);
2616 for (int i = 0; i < 10; i++) {
2617 a->Set(v8::Number::New(i), v8::Number::New(i));
2618 }
2619
2620 // Call function without any break points to ensure inlining is in place.
2621 const int kArgc = 1;
2622 v8::Handle<v8::Value> args[kArgc] = { a };
2623 foo->Call(env->Global(), kArgc, args);
2624
Steve Blocka7e24c12009-10-30 11:49:00 +00002625 // Setup break point and step through the function.
2626 SetBreakPoint(foo, 3);
2627 step_action = StepNext;
2628 break_point_hit_count = 0;
2629 foo->Call(env->Global(), kArgc, args);
2630
2631 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002632 CHECK_EQ(32, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002633
2634 v8::Debug::SetDebugEventListener(NULL);
2635 CheckDebuggerUnloaded();
2636}
2637
2638
Kristian Monsen25f61362010-05-21 11:50:48 +01002639// Test of the stepping mechanism for named load in a loop.
2640TEST(DebugStepNamedLoadLoop) {
2641 v8::HandleScope scope;
2642 DebugLocalContext env;
2643
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002644 // Register a debug event listener which steps and counts.
2645 v8::Debug::SetDebugEventListener(DebugEventStep);
2646
Kristian Monsen25f61362010-05-21 11:50:48 +01002647 // Create a function for testing stepping of named load.
2648 v8::Local<v8::Function> foo = CompileFunction(
2649 &env,
2650 "function foo() {\n"
2651 " var a = [];\n"
2652 " var s = \"\";\n"
2653 " for (var i = 0; i < 10; i++) {\n"
2654 " var v = new V(i, i + 1);\n"
2655 " v.y;\n"
2656 " a.length;\n" // Special case: array length.
2657 " s.length;\n" // Special case: string length.
2658 " }\n"
2659 "}\n"
2660 "function V(x, y) {\n"
2661 " this.x = x;\n"
2662 " this.y = y;\n"
2663 "}\n",
2664 "foo");
2665
2666 // Call function without any break points to ensure inlining is in place.
2667 foo->Call(env->Global(), 0, NULL);
2668
Kristian Monsen25f61362010-05-21 11:50:48 +01002669 // Setup break point and step through the function.
2670 SetBreakPoint(foo, 4);
2671 step_action = StepNext;
2672 break_point_hit_count = 0;
2673 foo->Call(env->Global(), 0, NULL);
2674
2675 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002676 CHECK_EQ(53, break_point_hit_count);
Kristian Monsen25f61362010-05-21 11:50:48 +01002677
2678 v8::Debug::SetDebugEventListener(NULL);
2679 CheckDebuggerUnloaded();
2680}
2681
2682
Iain Merrick75681382010-08-19 15:07:18 +01002683static void DoDebugStepNamedStoreLoop(int expected, bool full_compiler = true) {
2684 v8::HandleScope scope;
2685 DebugLocalContext env;
2686
2687 // Register a debug event listener which steps and counts before compiling the
2688 // function to ensure the full compiler is used.
2689 if (full_compiler) {
2690 v8::Debug::SetDebugEventListener(DebugEventStep);
2691 }
2692
2693 // Create a function for testing stepping of named store.
2694 v8::Local<v8::Function> foo = CompileFunction(
2695 &env,
2696 "function foo() {\n"
2697 " var a = {a:1};\n"
2698 " for (var i = 0; i < 10; i++) {\n"
2699 " a.a = 2\n"
2700 " }\n"
2701 "}\n",
2702 "foo");
2703
2704 // Call function without any break points to ensure inlining is in place.
2705 foo->Call(env->Global(), 0, NULL);
2706
2707 // Register a debug event listener which steps and counts after compiling the
2708 // function to ensure the optimizing compiler is used.
2709 if (!full_compiler) {
2710 v8::Debug::SetDebugEventListener(DebugEventStep);
2711 }
2712
2713 // Setup break point and step through the function.
2714 SetBreakPoint(foo, 3);
2715 step_action = StepNext;
2716 break_point_hit_count = 0;
2717 foo->Call(env->Global(), 0, NULL);
2718
2719 // With stepping all expected break locations are hit.
2720 CHECK_EQ(expected, break_point_hit_count);
2721
2722 v8::Debug::SetDebugEventListener(NULL);
2723 CheckDebuggerUnloaded();
2724}
2725
2726
2727// Test of the stepping mechanism for named load in a loop.
2728TEST(DebugStepNamedStoreLoopFull) {
2729 // With the full compiler it is possible to break on the for statement.
2730 DoDebugStepNamedStoreLoop(22);
2731}
2732
2733
2734// Test of the stepping mechanism for named load in a loop.
2735TEST(DebugStepNamedStoreLoopOptimizing) {
2736 // With the optimizing compiler it is not possible to break on the for
2737 // statement as it uses a local variable thus no IC's.
2738 DoDebugStepNamedStoreLoop(11, false);
2739}
2740
2741
Steve Blocka7e24c12009-10-30 11:49:00 +00002742// Test the stepping mechanism with different ICs.
2743TEST(DebugStepLinearMixedICs) {
2744 v8::HandleScope scope;
2745 DebugLocalContext env;
2746
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002747 // Register a debug event listener which steps and counts.
2748 v8::Debug::SetDebugEventListener(DebugEventStep);
2749
Steve Blocka7e24c12009-10-30 11:49:00 +00002750 // Create a function for testing stepping.
2751 v8::Local<v8::Function> foo = CompileFunction(&env,
2752 "function bar() {};"
2753 "function foo() {"
2754 " var x;"
2755 " var index='name';"
2756 " var y = {};"
2757 " a=1;b=2;x=a;y[index]=3;x=y[index];bar();}", "foo");
2758 SetBreakPoint(foo, 0);
2759
Steve Blocka7e24c12009-10-30 11:49:00 +00002760 step_action = StepIn;
2761 break_point_hit_count = 0;
2762 foo->Call(env->Global(), 0, NULL);
2763
2764 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002765 CHECK_EQ(11, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002766
2767 v8::Debug::SetDebugEventListener(NULL);
2768 CheckDebuggerUnloaded();
2769
2770 // Register a debug event listener which just counts.
2771 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2772
2773 SetBreakPoint(foo, 0);
2774 break_point_hit_count = 0;
2775 foo->Call(env->Global(), 0, NULL);
2776
2777 // Without stepping only active break points are hit.
2778 CHECK_EQ(1, break_point_hit_count);
2779
2780 v8::Debug::SetDebugEventListener(NULL);
2781 CheckDebuggerUnloaded();
2782}
2783
2784
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002785TEST(DebugStepDeclarations) {
2786 v8::HandleScope scope;
2787 DebugLocalContext env;
2788
2789 // Register a debug event listener which steps and counts.
2790 v8::Debug::SetDebugEventListener(DebugEventStep);
2791
2792 // Create a function for testing stepping.
2793 const char* src = "function foo() { "
2794 " var a;"
2795 " var b = 1;"
2796 " var c = foo;"
2797 " var d = Math.floor;"
2798 " var e = b + d(1.2);"
2799 "}";
2800 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2801 SetBreakPoint(foo, 0);
2802
2803 // Stepping through the declarations.
2804 step_action = StepIn;
2805 break_point_hit_count = 0;
2806 foo->Call(env->Global(), 0, NULL);
2807 CHECK_EQ(6, break_point_hit_count);
2808
2809 // Get rid of the debug event listener.
2810 v8::Debug::SetDebugEventListener(NULL);
2811 CheckDebuggerUnloaded();
2812}
2813
2814
2815TEST(DebugStepLocals) {
2816 v8::HandleScope scope;
2817 DebugLocalContext env;
2818
2819 // Register a debug event listener which steps and counts.
2820 v8::Debug::SetDebugEventListener(DebugEventStep);
2821
2822 // Create a function for testing stepping.
2823 const char* src = "function foo() { "
2824 " var a,b;"
2825 " a = 1;"
2826 " b = a + 2;"
2827 " b = 1 + 2 + 3;"
2828 " a = Math.floor(b);"
2829 "}";
2830 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2831 SetBreakPoint(foo, 0);
2832
2833 // Stepping through the declarations.
2834 step_action = StepIn;
2835 break_point_hit_count = 0;
2836 foo->Call(env->Global(), 0, NULL);
2837 CHECK_EQ(6, break_point_hit_count);
2838
2839 // Get rid of the debug event listener.
2840 v8::Debug::SetDebugEventListener(NULL);
2841 CheckDebuggerUnloaded();
2842}
2843
2844
Steve Blocka7e24c12009-10-30 11:49:00 +00002845TEST(DebugStepIf) {
2846 v8::HandleScope scope;
2847 DebugLocalContext env;
2848
2849 // Register a debug event listener which steps and counts.
2850 v8::Debug::SetDebugEventListener(DebugEventStep);
2851
2852 // Create a function for testing stepping.
2853 const int argc = 1;
2854 const char* src = "function foo(x) { "
2855 " a = 1;"
2856 " if (x) {"
2857 " b = 1;"
2858 " } else {"
2859 " c = 1;"
2860 " d = 1;"
2861 " }"
2862 "}";
2863 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2864 SetBreakPoint(foo, 0);
2865
2866 // Stepping through the true part.
2867 step_action = StepIn;
2868 break_point_hit_count = 0;
2869 v8::Handle<v8::Value> argv_true[argc] = { v8::True() };
2870 foo->Call(env->Global(), argc, argv_true);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002871 CHECK_EQ(4, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002872
2873 // Stepping through the false part.
2874 step_action = StepIn;
2875 break_point_hit_count = 0;
2876 v8::Handle<v8::Value> argv_false[argc] = { v8::False() };
2877 foo->Call(env->Global(), argc, argv_false);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002878 CHECK_EQ(5, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002879
2880 // Get rid of the debug event listener.
2881 v8::Debug::SetDebugEventListener(NULL);
2882 CheckDebuggerUnloaded();
2883}
2884
2885
2886TEST(DebugStepSwitch) {
2887 v8::HandleScope scope;
2888 DebugLocalContext env;
2889
2890 // Register a debug event listener which steps and counts.
2891 v8::Debug::SetDebugEventListener(DebugEventStep);
2892
2893 // Create a function for testing stepping.
2894 const int argc = 1;
2895 const char* src = "function foo(x) { "
2896 " a = 1;"
2897 " switch (x) {"
2898 " case 1:"
2899 " b = 1;"
2900 " case 2:"
2901 " c = 1;"
2902 " break;"
2903 " case 3:"
2904 " d = 1;"
2905 " e = 1;"
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002906 " f = 1;"
Steve Blocka7e24c12009-10-30 11:49:00 +00002907 " break;"
2908 " }"
2909 "}";
2910 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2911 SetBreakPoint(foo, 0);
2912
2913 // One case with fall-through.
2914 step_action = StepIn;
2915 break_point_hit_count = 0;
2916 v8::Handle<v8::Value> argv_1[argc] = { v8::Number::New(1) };
2917 foo->Call(env->Global(), argc, argv_1);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002918 CHECK_EQ(6, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002919
2920 // Another case.
2921 step_action = StepIn;
2922 break_point_hit_count = 0;
2923 v8::Handle<v8::Value> argv_2[argc] = { v8::Number::New(2) };
2924 foo->Call(env->Global(), argc, argv_2);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002925 CHECK_EQ(5, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002926
2927 // Last case.
2928 step_action = StepIn;
2929 break_point_hit_count = 0;
2930 v8::Handle<v8::Value> argv_3[argc] = { v8::Number::New(3) };
2931 foo->Call(env->Global(), argc, argv_3);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002932 CHECK_EQ(7, break_point_hit_count);
2933
2934 // Get rid of the debug event listener.
2935 v8::Debug::SetDebugEventListener(NULL);
2936 CheckDebuggerUnloaded();
2937}
2938
2939
2940TEST(DebugStepWhile) {
2941 v8::HandleScope scope;
2942 DebugLocalContext env;
2943
2944 // Register a debug event listener which steps and counts.
2945 v8::Debug::SetDebugEventListener(DebugEventStep);
2946
2947 // Create a function for testing stepping.
2948 const int argc = 1;
2949 const char* src = "function foo(x) { "
2950 " var a = 0;"
2951 " while (a < x) {"
2952 " a++;"
2953 " }"
2954 "}";
2955 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2956 SetBreakPoint(foo, 8); // "var a = 0;"
2957
2958 // Looping 10 times.
2959 step_action = StepIn;
2960 break_point_hit_count = 0;
2961 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
2962 foo->Call(env->Global(), argc, argv_10);
2963 CHECK_EQ(23, break_point_hit_count);
2964
2965 // Looping 100 times.
2966 step_action = StepIn;
2967 break_point_hit_count = 0;
2968 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
2969 foo->Call(env->Global(), argc, argv_100);
2970 CHECK_EQ(203, break_point_hit_count);
2971
2972 // Get rid of the debug event listener.
2973 v8::Debug::SetDebugEventListener(NULL);
2974 CheckDebuggerUnloaded();
2975}
2976
2977
2978TEST(DebugStepDoWhile) {
2979 v8::HandleScope scope;
2980 DebugLocalContext env;
2981
2982 // Register a debug event listener which steps and counts.
2983 v8::Debug::SetDebugEventListener(DebugEventStep);
2984
2985 // Create a function for testing stepping.
2986 const int argc = 1;
2987 const char* src = "function foo(x) { "
2988 " var a = 0;"
2989 " do {"
2990 " a++;"
2991 " } while (a < x)"
2992 "}";
2993 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2994 SetBreakPoint(foo, 8); // "var a = 0;"
2995
2996 // Looping 10 times.
2997 step_action = StepIn;
2998 break_point_hit_count = 0;
2999 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3000 foo->Call(env->Global(), argc, argv_10);
3001 CHECK_EQ(22, break_point_hit_count);
3002
3003 // Looping 100 times.
3004 step_action = StepIn;
3005 break_point_hit_count = 0;
3006 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3007 foo->Call(env->Global(), argc, argv_100);
3008 CHECK_EQ(202, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003009
3010 // Get rid of the debug event listener.
3011 v8::Debug::SetDebugEventListener(NULL);
3012 CheckDebuggerUnloaded();
3013}
3014
3015
3016TEST(DebugStepFor) {
3017 v8::HandleScope scope;
3018 DebugLocalContext env;
3019
3020 // Register a debug event listener which steps and counts.
3021 v8::Debug::SetDebugEventListener(DebugEventStep);
3022
3023 // Create a function for testing stepping.
3024 const int argc = 1;
3025 const char* src = "function foo(x) { "
3026 " a = 1;"
3027 " for (i = 0; i < x; i++) {"
3028 " b = 1;"
3029 " }"
3030 "}";
3031 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3032 SetBreakPoint(foo, 8); // "a = 1;"
3033
3034 // Looping 10 times.
3035 step_action = StepIn;
3036 break_point_hit_count = 0;
3037 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3038 foo->Call(env->Global(), argc, argv_10);
3039 CHECK_EQ(23, break_point_hit_count);
3040
3041 // Looping 100 times.
3042 step_action = StepIn;
3043 break_point_hit_count = 0;
3044 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3045 foo->Call(env->Global(), argc, argv_100);
3046 CHECK_EQ(203, break_point_hit_count);
3047
3048 // Get rid of the debug event listener.
3049 v8::Debug::SetDebugEventListener(NULL);
3050 CheckDebuggerUnloaded();
3051}
3052
3053
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003054TEST(DebugStepForContinue) {
3055 v8::HandleScope scope;
3056 DebugLocalContext env;
3057
3058 // Register a debug event listener which steps and counts.
3059 v8::Debug::SetDebugEventListener(DebugEventStep);
3060
3061 // Create a function for testing stepping.
3062 const int argc = 1;
3063 const char* src = "function foo(x) { "
3064 " var a = 0;"
3065 " var b = 0;"
3066 " var c = 0;"
3067 " for (var i = 0; i < x; i++) {"
3068 " a++;"
3069 " if (a % 2 == 0) continue;"
3070 " b++;"
3071 " c++;"
3072 " }"
3073 " return b;"
3074 "}";
3075 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3076 v8::Handle<v8::Value> result;
3077 SetBreakPoint(foo, 8); // "var a = 0;"
3078
3079 // Each loop generates 4 or 5 steps depending on whether a is equal.
3080
3081 // Looping 10 times.
3082 step_action = StepIn;
3083 break_point_hit_count = 0;
3084 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3085 result = foo->Call(env->Global(), argc, argv_10);
3086 CHECK_EQ(5, result->Int32Value());
3087 CHECK_EQ(50, break_point_hit_count);
3088
3089 // Looping 100 times.
3090 step_action = StepIn;
3091 break_point_hit_count = 0;
3092 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3093 result = foo->Call(env->Global(), argc, argv_100);
3094 CHECK_EQ(50, result->Int32Value());
3095 CHECK_EQ(455, break_point_hit_count);
3096
3097 // Get rid of the debug event listener.
3098 v8::Debug::SetDebugEventListener(NULL);
3099 CheckDebuggerUnloaded();
3100}
3101
3102
3103TEST(DebugStepForBreak) {
3104 v8::HandleScope scope;
3105 DebugLocalContext env;
3106
3107 // Register a debug event listener which steps and counts.
3108 v8::Debug::SetDebugEventListener(DebugEventStep);
3109
3110 // Create a function for testing stepping.
3111 const int argc = 1;
3112 const char* src = "function foo(x) { "
3113 " var a = 0;"
3114 " var b = 0;"
3115 " var c = 0;"
3116 " for (var i = 0; i < 1000; i++) {"
3117 " a++;"
3118 " if (a == x) break;"
3119 " b++;"
3120 " c++;"
3121 " }"
3122 " return b;"
3123 "}";
3124 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3125 v8::Handle<v8::Value> result;
3126 SetBreakPoint(foo, 8); // "var a = 0;"
3127
3128 // Each loop generates 5 steps except for the last (when break is executed)
3129 // which only generates 4.
3130
3131 // Looping 10 times.
3132 step_action = StepIn;
3133 break_point_hit_count = 0;
3134 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3135 result = foo->Call(env->Global(), argc, argv_10);
3136 CHECK_EQ(9, result->Int32Value());
3137 CHECK_EQ(53, break_point_hit_count);
3138
3139 // Looping 100 times.
3140 step_action = StepIn;
3141 break_point_hit_count = 0;
3142 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3143 result = foo->Call(env->Global(), argc, argv_100);
3144 CHECK_EQ(99, result->Int32Value());
3145 CHECK_EQ(503, break_point_hit_count);
3146
3147 // Get rid of the debug event listener.
3148 v8::Debug::SetDebugEventListener(NULL);
3149 CheckDebuggerUnloaded();
3150}
3151
3152
3153TEST(DebugStepForIn) {
3154 v8::HandleScope scope;
3155 DebugLocalContext env;
3156
3157 // Register a debug event listener which steps and counts.
3158 v8::Debug::SetDebugEventListener(DebugEventStep);
3159
3160 v8::Local<v8::Function> foo;
3161 const char* src_1 = "function foo() { "
3162 " var a = [1, 2];"
3163 " for (x in a) {"
3164 " b = 0;"
3165 " }"
3166 "}";
3167 foo = CompileFunction(&env, src_1, "foo");
3168 SetBreakPoint(foo, 0); // "var a = ..."
3169
3170 step_action = StepIn;
3171 break_point_hit_count = 0;
3172 foo->Call(env->Global(), 0, NULL);
3173 CHECK_EQ(6, break_point_hit_count);
3174
3175 const char* src_2 = "function foo() { "
3176 " var a = {a:[1, 2, 3]};"
3177 " for (x in a.a) {"
3178 " b = 0;"
3179 " }"
3180 "}";
3181 foo = CompileFunction(&env, src_2, "foo");
3182 SetBreakPoint(foo, 0); // "var a = ..."
3183
3184 step_action = StepIn;
3185 break_point_hit_count = 0;
3186 foo->Call(env->Global(), 0, NULL);
3187 CHECK_EQ(8, break_point_hit_count);
3188
3189 // Get rid of the debug event listener.
3190 v8::Debug::SetDebugEventListener(NULL);
3191 CheckDebuggerUnloaded();
3192}
3193
3194
3195TEST(DebugStepWith) {
3196 v8::HandleScope scope;
3197 DebugLocalContext env;
3198
3199 // Register a debug event listener which steps and counts.
3200 v8::Debug::SetDebugEventListener(DebugEventStep);
3201
3202 // Create a function for testing stepping.
3203 const char* src = "function foo(x) { "
3204 " var a = {};"
3205 " with (a) {}"
3206 " with (b) {}"
3207 "}";
3208 env->Global()->Set(v8::String::New("b"), v8::Object::New());
3209 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3210 v8::Handle<v8::Value> result;
3211 SetBreakPoint(foo, 8); // "var a = {};"
3212
3213 step_action = StepIn;
3214 break_point_hit_count = 0;
3215 foo->Call(env->Global(), 0, NULL);
3216 CHECK_EQ(4, break_point_hit_count);
3217
3218 // Get rid of the debug event listener.
3219 v8::Debug::SetDebugEventListener(NULL);
3220 CheckDebuggerUnloaded();
3221}
3222
3223
3224TEST(DebugConditional) {
3225 v8::HandleScope scope;
3226 DebugLocalContext env;
3227
3228 // Register a debug event listener which steps and counts.
3229 v8::Debug::SetDebugEventListener(DebugEventStep);
3230
3231 // Create a function for testing stepping.
3232 const char* src = "function foo(x) { "
3233 " var a;"
3234 " a = x ? 1 : 2;"
3235 " return a;"
3236 "}";
3237 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3238 SetBreakPoint(foo, 0); // "var a;"
3239
3240 step_action = StepIn;
3241 break_point_hit_count = 0;
3242 foo->Call(env->Global(), 0, NULL);
3243 CHECK_EQ(5, break_point_hit_count);
3244
3245 step_action = StepIn;
3246 break_point_hit_count = 0;
3247 const int argc = 1;
3248 v8::Handle<v8::Value> argv_true[argc] = { v8::True() };
3249 foo->Call(env->Global(), argc, argv_true);
3250 CHECK_EQ(5, break_point_hit_count);
3251
3252 // Get rid of the debug event listener.
3253 v8::Debug::SetDebugEventListener(NULL);
3254 CheckDebuggerUnloaded();
3255}
3256
3257
Steve Blocka7e24c12009-10-30 11:49:00 +00003258TEST(StepInOutSimple) {
3259 v8::HandleScope scope;
3260 DebugLocalContext env;
3261
3262 // Create a function for checking the function when hitting a break point.
3263 frame_function_name = CompileFunction(&env,
3264 frame_function_name_source,
3265 "frame_function_name");
3266
3267 // Register a debug event listener which steps and counts.
3268 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3269
3270 // Create functions for testing stepping.
3271 const char* src = "function a() {b();c();}; "
3272 "function b() {c();}; "
3273 "function c() {}; ";
3274 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3275 SetBreakPoint(a, 0);
3276
3277 // Step through invocation of a with step in.
3278 step_action = StepIn;
3279 break_point_hit_count = 0;
3280 expected_step_sequence = "abcbaca";
3281 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003282 CHECK_EQ(StrLength(expected_step_sequence),
3283 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003284
3285 // Step through invocation of a with step next.
3286 step_action = StepNext;
3287 break_point_hit_count = 0;
3288 expected_step_sequence = "aaa";
3289 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003290 CHECK_EQ(StrLength(expected_step_sequence),
3291 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003292
3293 // Step through invocation of a with step out.
3294 step_action = StepOut;
3295 break_point_hit_count = 0;
3296 expected_step_sequence = "a";
3297 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003298 CHECK_EQ(StrLength(expected_step_sequence),
3299 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003300
3301 // Get rid of the debug event listener.
3302 v8::Debug::SetDebugEventListener(NULL);
3303 CheckDebuggerUnloaded();
3304}
3305
3306
3307TEST(StepInOutTree) {
3308 v8::HandleScope scope;
3309 DebugLocalContext env;
3310
3311 // Create a function for checking the function when hitting a break point.
3312 frame_function_name = CompileFunction(&env,
3313 frame_function_name_source,
3314 "frame_function_name");
3315
3316 // Register a debug event listener which steps and counts.
3317 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3318
3319 // Create functions for testing stepping.
3320 const char* src = "function a() {b(c(d()),d());c(d());d()}; "
3321 "function b(x,y) {c();}; "
3322 "function c(x) {}; "
3323 "function d() {}; ";
3324 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3325 SetBreakPoint(a, 0);
3326
3327 // Step through invocation of a with step in.
3328 step_action = StepIn;
3329 break_point_hit_count = 0;
3330 expected_step_sequence = "adacadabcbadacada";
3331 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003332 CHECK_EQ(StrLength(expected_step_sequence),
3333 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003334
3335 // Step through invocation of a with step next.
3336 step_action = StepNext;
3337 break_point_hit_count = 0;
3338 expected_step_sequence = "aaaa";
3339 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003340 CHECK_EQ(StrLength(expected_step_sequence),
3341 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003342
3343 // Step through invocation of a with step out.
3344 step_action = StepOut;
3345 break_point_hit_count = 0;
3346 expected_step_sequence = "a";
3347 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003348 CHECK_EQ(StrLength(expected_step_sequence),
3349 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003350
3351 // Get rid of the debug event listener.
3352 v8::Debug::SetDebugEventListener(NULL);
3353 CheckDebuggerUnloaded(true);
3354}
3355
3356
3357TEST(StepInOutBranch) {
3358 v8::HandleScope scope;
3359 DebugLocalContext env;
3360
3361 // Create a function for checking the function when hitting a break point.
3362 frame_function_name = CompileFunction(&env,
3363 frame_function_name_source,
3364 "frame_function_name");
3365
3366 // Register a debug event listener which steps and counts.
3367 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3368
3369 // Create functions for testing stepping.
3370 const char* src = "function a() {b(false);c();}; "
3371 "function b(x) {if(x){c();};}; "
3372 "function c() {}; ";
3373 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3374 SetBreakPoint(a, 0);
3375
3376 // Step through invocation of a.
3377 step_action = StepIn;
3378 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003379 expected_step_sequence = "abbaca";
Steve Blocka7e24c12009-10-30 11:49:00 +00003380 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003381 CHECK_EQ(StrLength(expected_step_sequence),
3382 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003383
3384 // Get rid of the debug event listener.
3385 v8::Debug::SetDebugEventListener(NULL);
3386 CheckDebuggerUnloaded();
3387}
3388
3389
3390// Test that step in does not step into native functions.
3391TEST(DebugStepNatives) {
3392 v8::HandleScope scope;
3393 DebugLocalContext env;
3394
3395 // Create a function for testing stepping.
3396 v8::Local<v8::Function> foo = CompileFunction(
3397 &env,
3398 "function foo(){debugger;Math.sin(1);}",
3399 "foo");
3400
3401 // Register a debug event listener which steps and counts.
3402 v8::Debug::SetDebugEventListener(DebugEventStep);
3403
3404 step_action = StepIn;
3405 break_point_hit_count = 0;
3406 foo->Call(env->Global(), 0, NULL);
3407
3408 // With stepping all break locations are hit.
3409 CHECK_EQ(3, break_point_hit_count);
3410
3411 v8::Debug::SetDebugEventListener(NULL);
3412 CheckDebuggerUnloaded();
3413
3414 // Register a debug event listener which just counts.
3415 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3416
3417 break_point_hit_count = 0;
3418 foo->Call(env->Global(), 0, NULL);
3419
3420 // Without stepping only active break points are hit.
3421 CHECK_EQ(1, break_point_hit_count);
3422
3423 v8::Debug::SetDebugEventListener(NULL);
3424 CheckDebuggerUnloaded();
3425}
3426
3427
3428// Test that step in works with function.apply.
3429TEST(DebugStepFunctionApply) {
3430 v8::HandleScope scope;
3431 DebugLocalContext env;
3432
3433 // Create a function for testing stepping.
3434 v8::Local<v8::Function> foo = CompileFunction(
3435 &env,
3436 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3437 "function foo(){ debugger; bar.apply(this, [1,2,3]); }",
3438 "foo");
3439
3440 // Register a debug event listener which steps and counts.
3441 v8::Debug::SetDebugEventListener(DebugEventStep);
3442
3443 step_action = StepIn;
3444 break_point_hit_count = 0;
3445 foo->Call(env->Global(), 0, NULL);
3446
3447 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003448 CHECK_EQ(7, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003449
3450 v8::Debug::SetDebugEventListener(NULL);
3451 CheckDebuggerUnloaded();
3452
3453 // Register a debug event listener which just counts.
3454 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3455
3456 break_point_hit_count = 0;
3457 foo->Call(env->Global(), 0, NULL);
3458
3459 // Without stepping only the debugger statement is hit.
3460 CHECK_EQ(1, break_point_hit_count);
3461
3462 v8::Debug::SetDebugEventListener(NULL);
3463 CheckDebuggerUnloaded();
3464}
3465
3466
3467// Test that step in works with function.call.
3468TEST(DebugStepFunctionCall) {
3469 v8::HandleScope scope;
3470 DebugLocalContext env;
3471
3472 // Create a function for testing stepping.
3473 v8::Local<v8::Function> foo = CompileFunction(
3474 &env,
3475 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3476 "function foo(a){ debugger;"
3477 " if (a) {"
3478 " bar.call(this, 1, 2, 3);"
3479 " } else {"
3480 " bar.call(this, 0);"
3481 " }"
3482 "}",
3483 "foo");
3484
3485 // Register a debug event listener which steps and counts.
3486 v8::Debug::SetDebugEventListener(DebugEventStep);
3487 step_action = StepIn;
3488
3489 // Check stepping where the if condition in bar is false.
3490 break_point_hit_count = 0;
3491 foo->Call(env->Global(), 0, NULL);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003492 CHECK_EQ(6, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003493
3494 // Check stepping where the if condition in bar is true.
3495 break_point_hit_count = 0;
3496 const int argc = 1;
3497 v8::Handle<v8::Value> argv[argc] = { v8::True() };
3498 foo->Call(env->Global(), argc, argv);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003499 CHECK_EQ(8, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003500
3501 v8::Debug::SetDebugEventListener(NULL);
3502 CheckDebuggerUnloaded();
3503
3504 // Register a debug event listener which just counts.
3505 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3506
3507 break_point_hit_count = 0;
3508 foo->Call(env->Global(), 0, NULL);
3509
3510 // Without stepping only the debugger statement is hit.
3511 CHECK_EQ(1, break_point_hit_count);
3512
3513 v8::Debug::SetDebugEventListener(NULL);
3514 CheckDebuggerUnloaded();
3515}
3516
3517
Steve Blockd0582a62009-12-15 09:54:21 +00003518// Tests that breakpoint will be hit if it's set in script.
3519TEST(PauseInScript) {
3520 v8::HandleScope scope;
3521 DebugLocalContext env;
3522 env.ExposeDebug();
3523
3524 // Register a debug event listener which counts.
3525 v8::Debug::SetDebugEventListener(DebugEventCounter);
3526
3527 // Create a script that returns a function.
3528 const char* src = "(function (evt) {})";
3529 const char* script_name = "StepInHandlerTest";
3530
3531 // Set breakpoint in the script.
3532 SetScriptBreakPointByNameFromJS(script_name, 0, -1);
3533 break_point_hit_count = 0;
3534
3535 v8::ScriptOrigin origin(v8::String::New(script_name), v8::Integer::New(0));
3536 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(src),
3537 &origin);
3538 v8::Local<v8::Value> r = script->Run();
3539
3540 CHECK(r->IsFunction());
3541 CHECK_EQ(1, break_point_hit_count);
3542
3543 // Get rid of the debug event listener.
3544 v8::Debug::SetDebugEventListener(NULL);
3545 CheckDebuggerUnloaded();
3546}
3547
3548
Steve Blocka7e24c12009-10-30 11:49:00 +00003549// Test break on exceptions. For each exception break combination the number
3550// of debug event exception callbacks and message callbacks are collected. The
3551// number of debug event exception callbacks are used to check that the
3552// debugger is called correctly and the number of message callbacks is used to
3553// check that uncaught exceptions are still returned even if there is a break
3554// for them.
3555TEST(BreakOnException) {
3556 v8::HandleScope scope;
3557 DebugLocalContext env;
3558 env.ExposeDebug();
3559
3560 v8::internal::Top::TraceException(false);
3561
3562 // Create functions for testing break on exception.
3563 v8::Local<v8::Function> throws =
3564 CompileFunction(&env, "function throws(){throw 1;}", "throws");
3565 v8::Local<v8::Function> caught =
3566 CompileFunction(&env,
3567 "function caught(){try {throws();} catch(e) {};}",
3568 "caught");
3569 v8::Local<v8::Function> notCaught =
3570 CompileFunction(&env, "function notCaught(){throws();}", "notCaught");
3571
3572 v8::V8::AddMessageListener(MessageCallbackCount);
3573 v8::Debug::SetDebugEventListener(DebugEventCounter);
3574
3575 // Initial state should be break on uncaught exception.
3576 DebugEventCounterClear();
3577 MessageCallbackCountClear();
3578 caught->Call(env->Global(), 0, NULL);
3579 CHECK_EQ(0, exception_hit_count);
3580 CHECK_EQ(0, uncaught_exception_hit_count);
3581 CHECK_EQ(0, message_callback_count);
3582 notCaught->Call(env->Global(), 0, NULL);
3583 CHECK_EQ(1, exception_hit_count);
3584 CHECK_EQ(1, uncaught_exception_hit_count);
3585 CHECK_EQ(1, message_callback_count);
3586
3587 // No break on exception
3588 DebugEventCounterClear();
3589 MessageCallbackCountClear();
3590 ChangeBreakOnException(false, false);
3591 caught->Call(env->Global(), 0, NULL);
3592 CHECK_EQ(0, exception_hit_count);
3593 CHECK_EQ(0, uncaught_exception_hit_count);
3594 CHECK_EQ(0, message_callback_count);
3595 notCaught->Call(env->Global(), 0, NULL);
3596 CHECK_EQ(0, exception_hit_count);
3597 CHECK_EQ(0, uncaught_exception_hit_count);
3598 CHECK_EQ(1, message_callback_count);
3599
3600 // Break on uncaught exception
3601 DebugEventCounterClear();
3602 MessageCallbackCountClear();
3603 ChangeBreakOnException(false, true);
3604 caught->Call(env->Global(), 0, NULL);
3605 CHECK_EQ(0, exception_hit_count);
3606 CHECK_EQ(0, uncaught_exception_hit_count);
3607 CHECK_EQ(0, message_callback_count);
3608 notCaught->Call(env->Global(), 0, NULL);
3609 CHECK_EQ(1, exception_hit_count);
3610 CHECK_EQ(1, uncaught_exception_hit_count);
3611 CHECK_EQ(1, message_callback_count);
3612
3613 // Break on exception and uncaught exception
3614 DebugEventCounterClear();
3615 MessageCallbackCountClear();
3616 ChangeBreakOnException(true, true);
3617 caught->Call(env->Global(), 0, NULL);
3618 CHECK_EQ(1, exception_hit_count);
3619 CHECK_EQ(0, uncaught_exception_hit_count);
3620 CHECK_EQ(0, message_callback_count);
3621 notCaught->Call(env->Global(), 0, NULL);
3622 CHECK_EQ(2, exception_hit_count);
3623 CHECK_EQ(1, uncaught_exception_hit_count);
3624 CHECK_EQ(1, message_callback_count);
3625
3626 // Break on exception
3627 DebugEventCounterClear();
3628 MessageCallbackCountClear();
3629 ChangeBreakOnException(true, false);
3630 caught->Call(env->Global(), 0, NULL);
3631 CHECK_EQ(1, exception_hit_count);
3632 CHECK_EQ(0, uncaught_exception_hit_count);
3633 CHECK_EQ(0, message_callback_count);
3634 notCaught->Call(env->Global(), 0, NULL);
3635 CHECK_EQ(2, exception_hit_count);
3636 CHECK_EQ(1, uncaught_exception_hit_count);
3637 CHECK_EQ(1, message_callback_count);
3638
3639 // No break on exception using JavaScript
3640 DebugEventCounterClear();
3641 MessageCallbackCountClear();
3642 ChangeBreakOnExceptionFromJS(false, false);
3643 caught->Call(env->Global(), 0, NULL);
3644 CHECK_EQ(0, exception_hit_count);
3645 CHECK_EQ(0, uncaught_exception_hit_count);
3646 CHECK_EQ(0, message_callback_count);
3647 notCaught->Call(env->Global(), 0, NULL);
3648 CHECK_EQ(0, exception_hit_count);
3649 CHECK_EQ(0, uncaught_exception_hit_count);
3650 CHECK_EQ(1, message_callback_count);
3651
3652 // Break on uncaught exception using JavaScript
3653 DebugEventCounterClear();
3654 MessageCallbackCountClear();
3655 ChangeBreakOnExceptionFromJS(false, true);
3656 caught->Call(env->Global(), 0, NULL);
3657 CHECK_EQ(0, exception_hit_count);
3658 CHECK_EQ(0, uncaught_exception_hit_count);
3659 CHECK_EQ(0, message_callback_count);
3660 notCaught->Call(env->Global(), 0, NULL);
3661 CHECK_EQ(1, exception_hit_count);
3662 CHECK_EQ(1, uncaught_exception_hit_count);
3663 CHECK_EQ(1, message_callback_count);
3664
3665 // Break on exception and uncaught exception using JavaScript
3666 DebugEventCounterClear();
3667 MessageCallbackCountClear();
3668 ChangeBreakOnExceptionFromJS(true, true);
3669 caught->Call(env->Global(), 0, NULL);
3670 CHECK_EQ(1, exception_hit_count);
3671 CHECK_EQ(0, message_callback_count);
3672 CHECK_EQ(0, uncaught_exception_hit_count);
3673 notCaught->Call(env->Global(), 0, NULL);
3674 CHECK_EQ(2, exception_hit_count);
3675 CHECK_EQ(1, uncaught_exception_hit_count);
3676 CHECK_EQ(1, message_callback_count);
3677
3678 // Break on exception using JavaScript
3679 DebugEventCounterClear();
3680 MessageCallbackCountClear();
3681 ChangeBreakOnExceptionFromJS(true, false);
3682 caught->Call(env->Global(), 0, NULL);
3683 CHECK_EQ(1, exception_hit_count);
3684 CHECK_EQ(0, uncaught_exception_hit_count);
3685 CHECK_EQ(0, message_callback_count);
3686 notCaught->Call(env->Global(), 0, NULL);
3687 CHECK_EQ(2, exception_hit_count);
3688 CHECK_EQ(1, uncaught_exception_hit_count);
3689 CHECK_EQ(1, message_callback_count);
3690
3691 v8::Debug::SetDebugEventListener(NULL);
3692 CheckDebuggerUnloaded();
3693 v8::V8::RemoveMessageListeners(MessageCallbackCount);
3694}
3695
3696
3697// Test break on exception from compiler errors. When compiling using
3698// v8::Script::Compile there is no JavaScript stack whereas when compiling using
3699// eval there are JavaScript frames.
3700TEST(BreakOnCompileException) {
3701 v8::HandleScope scope;
3702 DebugLocalContext env;
3703
3704 v8::internal::Top::TraceException(false);
3705
3706 // Create a function for checking the function when hitting a break point.
3707 frame_count = CompileFunction(&env, frame_count_source, "frame_count");
3708
3709 v8::V8::AddMessageListener(MessageCallbackCount);
3710 v8::Debug::SetDebugEventListener(DebugEventCounter);
3711
3712 DebugEventCounterClear();
3713 MessageCallbackCountClear();
3714
3715 // Check initial state.
3716 CHECK_EQ(0, exception_hit_count);
3717 CHECK_EQ(0, uncaught_exception_hit_count);
3718 CHECK_EQ(0, message_callback_count);
3719 CHECK_EQ(-1, last_js_stack_height);
3720
3721 // Throws SyntaxError: Unexpected end of input
3722 v8::Script::Compile(v8::String::New("+++"));
3723 CHECK_EQ(1, exception_hit_count);
3724 CHECK_EQ(1, uncaught_exception_hit_count);
3725 CHECK_EQ(1, message_callback_count);
3726 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
3727
3728 // Throws SyntaxError: Unexpected identifier
3729 v8::Script::Compile(v8::String::New("x x"));
3730 CHECK_EQ(2, exception_hit_count);
3731 CHECK_EQ(2, uncaught_exception_hit_count);
3732 CHECK_EQ(2, message_callback_count);
3733 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
3734
3735 // Throws SyntaxError: Unexpected end of input
3736 v8::Script::Compile(v8::String::New("eval('+++')"))->Run();
3737 CHECK_EQ(3, exception_hit_count);
3738 CHECK_EQ(3, uncaught_exception_hit_count);
3739 CHECK_EQ(3, message_callback_count);
3740 CHECK_EQ(1, last_js_stack_height);
3741
3742 // Throws SyntaxError: Unexpected identifier
3743 v8::Script::Compile(v8::String::New("eval('x x')"))->Run();
3744 CHECK_EQ(4, exception_hit_count);
3745 CHECK_EQ(4, uncaught_exception_hit_count);
3746 CHECK_EQ(4, message_callback_count);
3747 CHECK_EQ(1, last_js_stack_height);
3748}
3749
3750
3751TEST(StepWithException) {
3752 v8::HandleScope scope;
3753 DebugLocalContext env;
3754
3755 // Create a function for checking the function when hitting a break point.
3756 frame_function_name = CompileFunction(&env,
3757 frame_function_name_source,
3758 "frame_function_name");
3759
3760 // Register a debug event listener which steps and counts.
3761 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3762
3763 // Create functions for testing stepping.
3764 const char* src = "function a() { n(); }; "
3765 "function b() { c(); }; "
3766 "function c() { n(); }; "
3767 "function d() { x = 1; try { e(); } catch(x) { x = 2; } }; "
3768 "function e() { n(); }; "
3769 "function f() { x = 1; try { g(); } catch(x) { x = 2; } }; "
3770 "function g() { h(); }; "
3771 "function h() { x = 1; throw 1; }; ";
3772
3773 // Step through invocation of a.
3774 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3775 SetBreakPoint(a, 0);
3776 step_action = StepIn;
3777 break_point_hit_count = 0;
3778 expected_step_sequence = "aa";
3779 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003780 CHECK_EQ(StrLength(expected_step_sequence),
3781 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003782
3783 // Step through invocation of b + c.
3784 v8::Local<v8::Function> b = CompileFunction(&env, src, "b");
3785 SetBreakPoint(b, 0);
3786 step_action = StepIn;
3787 break_point_hit_count = 0;
3788 expected_step_sequence = "bcc";
3789 b->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003790 CHECK_EQ(StrLength(expected_step_sequence),
3791 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003792 // Step through invocation of d + e.
3793 v8::Local<v8::Function> d = CompileFunction(&env, src, "d");
3794 SetBreakPoint(d, 0);
3795 ChangeBreakOnException(false, true);
3796 step_action = StepIn;
3797 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003798 expected_step_sequence = "ddedd";
Steve Blocka7e24c12009-10-30 11:49:00 +00003799 d->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003800 CHECK_EQ(StrLength(expected_step_sequence),
3801 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003802
3803 // Step through invocation of d + e now with break on caught exceptions.
3804 ChangeBreakOnException(true, true);
3805 step_action = StepIn;
3806 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003807 expected_step_sequence = "ddeedd";
Steve Blocka7e24c12009-10-30 11:49:00 +00003808 d->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003809 CHECK_EQ(StrLength(expected_step_sequence),
3810 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003811
3812 // Step through invocation of f + g + h.
3813 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
3814 SetBreakPoint(f, 0);
3815 ChangeBreakOnException(false, true);
3816 step_action = StepIn;
3817 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003818 expected_step_sequence = "ffghhff";
Steve Blocka7e24c12009-10-30 11:49:00 +00003819 f->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003820 CHECK_EQ(StrLength(expected_step_sequence),
3821 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003822
3823 // Step through invocation of f + g + h now with break on caught exceptions.
3824 ChangeBreakOnException(true, true);
3825 step_action = StepIn;
3826 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003827 expected_step_sequence = "ffghhhff";
Steve Blocka7e24c12009-10-30 11:49:00 +00003828 f->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003829 CHECK_EQ(StrLength(expected_step_sequence),
3830 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003831
3832 // Get rid of the debug event listener.
3833 v8::Debug::SetDebugEventListener(NULL);
3834 CheckDebuggerUnloaded();
3835}
3836
3837
3838TEST(DebugBreak) {
3839 v8::HandleScope scope;
3840 DebugLocalContext env;
3841
3842 // This test should be run with option --verify-heap. As --verify-heap is
3843 // only available in debug mode only check for it in that case.
3844#ifdef DEBUG
3845 CHECK(v8::internal::FLAG_verify_heap);
3846#endif
3847
3848 // Register a debug event listener which sets the break flag and counts.
3849 v8::Debug::SetDebugEventListener(DebugEventBreak);
3850
3851 // Create a function for testing stepping.
3852 const char* src = "function f0() {}"
3853 "function f1(x1) {}"
3854 "function f2(x1,x2) {}"
3855 "function f3(x1,x2,x3) {}";
3856 v8::Local<v8::Function> f0 = CompileFunction(&env, src, "f0");
3857 v8::Local<v8::Function> f1 = CompileFunction(&env, src, "f1");
3858 v8::Local<v8::Function> f2 = CompileFunction(&env, src, "f2");
3859 v8::Local<v8::Function> f3 = CompileFunction(&env, src, "f3");
3860
3861 // Call the function to make sure it is compiled.
3862 v8::Handle<v8::Value> argv[] = { v8::Number::New(1),
3863 v8::Number::New(1),
3864 v8::Number::New(1),
3865 v8::Number::New(1) };
3866
3867 // Call all functions to make sure that they are compiled.
3868 f0->Call(env->Global(), 0, NULL);
3869 f1->Call(env->Global(), 0, NULL);
3870 f2->Call(env->Global(), 0, NULL);
3871 f3->Call(env->Global(), 0, NULL);
3872
3873 // Set the debug break flag.
3874 v8::Debug::DebugBreak();
3875
3876 // Call all functions with different argument count.
3877 break_point_hit_count = 0;
3878 for (unsigned int i = 0; i < ARRAY_SIZE(argv); i++) {
3879 f0->Call(env->Global(), i, argv);
3880 f1->Call(env->Global(), i, argv);
3881 f2->Call(env->Global(), i, argv);
3882 f3->Call(env->Global(), i, argv);
3883 }
3884
3885 // One break for each function called.
3886 CHECK_EQ(4 * ARRAY_SIZE(argv), break_point_hit_count);
3887
3888 // Get rid of the debug event listener.
3889 v8::Debug::SetDebugEventListener(NULL);
3890 CheckDebuggerUnloaded();
3891}
3892
3893
3894// Test to ensure that JavaScript code keeps running while the debug break
3895// through the stack limit flag is set but breaks are disabled.
3896TEST(DisableBreak) {
3897 v8::HandleScope scope;
3898 DebugLocalContext env;
3899
3900 // Register a debug event listener which sets the break flag and counts.
3901 v8::Debug::SetDebugEventListener(DebugEventCounter);
3902
3903 // Create a function for testing stepping.
3904 const char* src = "function f() {g()};function g(){i=0; while(i<10){i++}}";
3905 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
3906
3907 // Set the debug break flag.
3908 v8::Debug::DebugBreak();
3909
3910 // Call all functions with different argument count.
3911 break_point_hit_count = 0;
3912 f->Call(env->Global(), 0, NULL);
3913 CHECK_EQ(1, break_point_hit_count);
3914
3915 {
3916 v8::Debug::DebugBreak();
3917 v8::internal::DisableBreak disable_break(true);
3918 f->Call(env->Global(), 0, NULL);
3919 CHECK_EQ(1, break_point_hit_count);
3920 }
3921
3922 f->Call(env->Global(), 0, NULL);
3923 CHECK_EQ(2, break_point_hit_count);
3924
3925 // Get rid of the debug event listener.
3926 v8::Debug::SetDebugEventListener(NULL);
3927 CheckDebuggerUnloaded();
3928}
3929
Leon Clarkee46be812010-01-19 14:06:41 +00003930static const char* kSimpleExtensionSource =
3931 "(function Foo() {"
3932 " return 4;"
3933 "})() ";
3934
3935// http://crbug.com/28933
3936// Test that debug break is disabled when bootstrapper is active.
3937TEST(NoBreakWhenBootstrapping) {
3938 v8::HandleScope scope;
3939
3940 // Register a debug event listener which sets the break flag and counts.
3941 v8::Debug::SetDebugEventListener(DebugEventCounter);
3942
3943 // Set the debug break flag.
3944 v8::Debug::DebugBreak();
3945 break_point_hit_count = 0;
3946 {
3947 // Create a context with an extension to make sure that some JavaScript
3948 // code is executed during bootstrapping.
3949 v8::RegisterExtension(new v8::Extension("simpletest",
3950 kSimpleExtensionSource));
3951 const char* extension_names[] = { "simpletest" };
3952 v8::ExtensionConfiguration extensions(1, extension_names);
3953 v8::Persistent<v8::Context> context = v8::Context::New(&extensions);
3954 context.Dispose();
3955 }
3956 // Check that no DebugBreak events occured during the context creation.
3957 CHECK_EQ(0, break_point_hit_count);
3958
3959 // Get rid of the debug event listener.
3960 v8::Debug::SetDebugEventListener(NULL);
3961 CheckDebuggerUnloaded();
3962}
Steve Blocka7e24c12009-10-30 11:49:00 +00003963
3964static v8::Handle<v8::Array> NamedEnum(const v8::AccessorInfo&) {
3965 v8::Handle<v8::Array> result = v8::Array::New(3);
3966 result->Set(v8::Integer::New(0), v8::String::New("a"));
3967 result->Set(v8::Integer::New(1), v8::String::New("b"));
3968 result->Set(v8::Integer::New(2), v8::String::New("c"));
3969 return result;
3970}
3971
3972
3973static v8::Handle<v8::Array> IndexedEnum(const v8::AccessorInfo&) {
3974 v8::Handle<v8::Array> result = v8::Array::New(2);
3975 result->Set(v8::Integer::New(0), v8::Number::New(1));
3976 result->Set(v8::Integer::New(1), v8::Number::New(10));
3977 return result;
3978}
3979
3980
3981static v8::Handle<v8::Value> NamedGetter(v8::Local<v8::String> name,
3982 const v8::AccessorInfo& info) {
3983 v8::String::AsciiValue n(name);
3984 if (strcmp(*n, "a") == 0) {
3985 return v8::String::New("AA");
3986 } else if (strcmp(*n, "b") == 0) {
3987 return v8::String::New("BB");
3988 } else if (strcmp(*n, "c") == 0) {
3989 return v8::String::New("CC");
3990 } else {
3991 return v8::Undefined();
3992 }
3993
3994 return name;
3995}
3996
3997
3998static v8::Handle<v8::Value> IndexedGetter(uint32_t index,
3999 const v8::AccessorInfo& info) {
4000 return v8::Number::New(index + 1);
4001}
4002
4003
4004TEST(InterceptorPropertyMirror) {
4005 // Create a V8 environment with debug access.
4006 v8::HandleScope scope;
4007 DebugLocalContext env;
4008 env.ExposeDebug();
4009
4010 // Create object with named interceptor.
4011 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
4012 named->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
4013 env->Global()->Set(v8::String::New("intercepted_named"),
4014 named->NewInstance());
4015
4016 // Create object with indexed interceptor.
4017 v8::Handle<v8::ObjectTemplate> indexed = v8::ObjectTemplate::New();
4018 indexed->SetIndexedPropertyHandler(IndexedGetter,
4019 NULL,
4020 NULL,
4021 NULL,
4022 IndexedEnum);
4023 env->Global()->Set(v8::String::New("intercepted_indexed"),
4024 indexed->NewInstance());
4025
4026 // Create object with both named and indexed interceptor.
4027 v8::Handle<v8::ObjectTemplate> both = v8::ObjectTemplate::New();
4028 both->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
4029 both->SetIndexedPropertyHandler(IndexedGetter, NULL, NULL, NULL, IndexedEnum);
4030 env->Global()->Set(v8::String::New("intercepted_both"), both->NewInstance());
4031
4032 // Get mirrors for the three objects with interceptor.
4033 CompileRun(
4034 "named_mirror = debug.MakeMirror(intercepted_named);"
4035 "indexed_mirror = debug.MakeMirror(intercepted_indexed);"
4036 "both_mirror = debug.MakeMirror(intercepted_both)");
4037 CHECK(CompileRun(
4038 "named_mirror instanceof debug.ObjectMirror")->BooleanValue());
4039 CHECK(CompileRun(
4040 "indexed_mirror instanceof debug.ObjectMirror")->BooleanValue());
4041 CHECK(CompileRun(
4042 "both_mirror instanceof debug.ObjectMirror")->BooleanValue());
4043
4044 // Get the property names from the interceptors
4045 CompileRun(
4046 "named_names = named_mirror.propertyNames();"
4047 "indexed_names = indexed_mirror.propertyNames();"
4048 "both_names = both_mirror.propertyNames()");
4049 CHECK_EQ(3, CompileRun("named_names.length")->Int32Value());
4050 CHECK_EQ(2, CompileRun("indexed_names.length")->Int32Value());
4051 CHECK_EQ(5, CompileRun("both_names.length")->Int32Value());
4052
4053 // Check the expected number of properties.
4054 const char* source;
4055 source = "named_mirror.properties().length";
4056 CHECK_EQ(3, CompileRun(source)->Int32Value());
4057
4058 source = "indexed_mirror.properties().length";
4059 CHECK_EQ(2, CompileRun(source)->Int32Value());
4060
4061 source = "both_mirror.properties().length";
4062 CHECK_EQ(5, CompileRun(source)->Int32Value());
4063
4064 // 1 is PropertyKind.Named;
4065 source = "both_mirror.properties(1).length";
4066 CHECK_EQ(3, CompileRun(source)->Int32Value());
4067
4068 // 2 is PropertyKind.Indexed;
4069 source = "both_mirror.properties(2).length";
4070 CHECK_EQ(2, CompileRun(source)->Int32Value());
4071
4072 // 3 is PropertyKind.Named | PropertyKind.Indexed;
4073 source = "both_mirror.properties(3).length";
4074 CHECK_EQ(5, CompileRun(source)->Int32Value());
4075
4076 // Get the interceptor properties for the object with only named interceptor.
4077 CompileRun("named_values = named_mirror.properties()");
4078
4079 // Check that the properties are interceptor properties.
4080 for (int i = 0; i < 3; i++) {
4081 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4082 OS::SNPrintF(buffer,
4083 "named_values[%d] instanceof debug.PropertyMirror", i);
4084 CHECK(CompileRun(buffer.start())->BooleanValue());
4085
4086 // 4 is PropertyType.Interceptor
4087 OS::SNPrintF(buffer, "named_values[%d].propertyType()", i);
4088 CHECK_EQ(4, CompileRun(buffer.start())->Int32Value());
4089
4090 OS::SNPrintF(buffer, "named_values[%d].isNative()", i);
4091 CHECK(CompileRun(buffer.start())->BooleanValue());
4092 }
4093
4094 // Get the interceptor properties for the object with only indexed
4095 // interceptor.
4096 CompileRun("indexed_values = indexed_mirror.properties()");
4097
4098 // Check that the properties are interceptor properties.
4099 for (int i = 0; i < 2; i++) {
4100 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4101 OS::SNPrintF(buffer,
4102 "indexed_values[%d] instanceof debug.PropertyMirror", i);
4103 CHECK(CompileRun(buffer.start())->BooleanValue());
4104 }
4105
4106 // Get the interceptor properties for the object with both types of
4107 // interceptors.
4108 CompileRun("both_values = both_mirror.properties()");
4109
4110 // Check that the properties are interceptor properties.
4111 for (int i = 0; i < 5; i++) {
4112 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4113 OS::SNPrintF(buffer, "both_values[%d] instanceof debug.PropertyMirror", i);
4114 CHECK(CompileRun(buffer.start())->BooleanValue());
4115 }
4116
4117 // Check the property names.
4118 source = "both_values[0].name() == 'a'";
4119 CHECK(CompileRun(source)->BooleanValue());
4120
4121 source = "both_values[1].name() == 'b'";
4122 CHECK(CompileRun(source)->BooleanValue());
4123
4124 source = "both_values[2].name() == 'c'";
4125 CHECK(CompileRun(source)->BooleanValue());
4126
4127 source = "both_values[3].name() == 1";
4128 CHECK(CompileRun(source)->BooleanValue());
4129
4130 source = "both_values[4].name() == 10";
4131 CHECK(CompileRun(source)->BooleanValue());
4132}
4133
4134
4135TEST(HiddenPrototypePropertyMirror) {
4136 // Create a V8 environment with debug access.
4137 v8::HandleScope scope;
4138 DebugLocalContext env;
4139 env.ExposeDebug();
4140
4141 v8::Handle<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
4142 t0->InstanceTemplate()->Set(v8::String::New("x"), v8::Number::New(0));
4143 v8::Handle<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
4144 t1->SetHiddenPrototype(true);
4145 t1->InstanceTemplate()->Set(v8::String::New("y"), v8::Number::New(1));
4146 v8::Handle<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
4147 t2->SetHiddenPrototype(true);
4148 t2->InstanceTemplate()->Set(v8::String::New("z"), v8::Number::New(2));
4149 v8::Handle<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
4150 t3->InstanceTemplate()->Set(v8::String::New("u"), v8::Number::New(3));
4151
4152 // Create object and set them on the global object.
4153 v8::Handle<v8::Object> o0 = t0->GetFunction()->NewInstance();
4154 env->Global()->Set(v8::String::New("o0"), o0);
4155 v8::Handle<v8::Object> o1 = t1->GetFunction()->NewInstance();
4156 env->Global()->Set(v8::String::New("o1"), o1);
4157 v8::Handle<v8::Object> o2 = t2->GetFunction()->NewInstance();
4158 env->Global()->Set(v8::String::New("o2"), o2);
4159 v8::Handle<v8::Object> o3 = t3->GetFunction()->NewInstance();
4160 env->Global()->Set(v8::String::New("o3"), o3);
4161
4162 // Get mirrors for the four objects.
4163 CompileRun(
4164 "o0_mirror = debug.MakeMirror(o0);"
4165 "o1_mirror = debug.MakeMirror(o1);"
4166 "o2_mirror = debug.MakeMirror(o2);"
4167 "o3_mirror = debug.MakeMirror(o3)");
4168 CHECK(CompileRun("o0_mirror instanceof debug.ObjectMirror")->BooleanValue());
4169 CHECK(CompileRun("o1_mirror instanceof debug.ObjectMirror")->BooleanValue());
4170 CHECK(CompileRun("o2_mirror instanceof debug.ObjectMirror")->BooleanValue());
4171 CHECK(CompileRun("o3_mirror instanceof debug.ObjectMirror")->BooleanValue());
4172
4173 // Check that each object has one property.
4174 CHECK_EQ(1, CompileRun(
4175 "o0_mirror.propertyNames().length")->Int32Value());
4176 CHECK_EQ(1, CompileRun(
4177 "o1_mirror.propertyNames().length")->Int32Value());
4178 CHECK_EQ(1, CompileRun(
4179 "o2_mirror.propertyNames().length")->Int32Value());
4180 CHECK_EQ(1, CompileRun(
4181 "o3_mirror.propertyNames().length")->Int32Value());
4182
4183 // Set o1 as prototype for o0. o1 has the hidden prototype flag so all
4184 // properties on o1 should be seen on o0.
4185 o0->Set(v8::String::New("__proto__"), o1);
4186 CHECK_EQ(2, CompileRun(
4187 "o0_mirror.propertyNames().length")->Int32Value());
4188 CHECK_EQ(0, CompileRun(
4189 "o0_mirror.property('x').value().value()")->Int32Value());
4190 CHECK_EQ(1, CompileRun(
4191 "o0_mirror.property('y').value().value()")->Int32Value());
4192
4193 // Set o2 as prototype for o0 (it will end up after o1 as o1 has the hidden
4194 // prototype flag. o2 also has the hidden prototype flag so all properties
4195 // on o2 should be seen on o0 as well as properties on o1.
4196 o0->Set(v8::String::New("__proto__"), o2);
4197 CHECK_EQ(3, CompileRun(
4198 "o0_mirror.propertyNames().length")->Int32Value());
4199 CHECK_EQ(0, CompileRun(
4200 "o0_mirror.property('x').value().value()")->Int32Value());
4201 CHECK_EQ(1, CompileRun(
4202 "o0_mirror.property('y').value().value()")->Int32Value());
4203 CHECK_EQ(2, CompileRun(
4204 "o0_mirror.property('z').value().value()")->Int32Value());
4205
4206 // Set o3 as prototype for o0 (it will end up after o1 and o2 as both o1 and
4207 // o2 has the hidden prototype flag. o3 does not have the hidden prototype
4208 // flag so properties on o3 should not be seen on o0 whereas the properties
4209 // from o1 and o2 should still be seen on o0.
4210 // Final prototype chain: o0 -> o1 -> o2 -> o3
4211 // Hidden prototypes: ^^ ^^
4212 o0->Set(v8::String::New("__proto__"), o3);
4213 CHECK_EQ(3, CompileRun(
4214 "o0_mirror.propertyNames().length")->Int32Value());
4215 CHECK_EQ(1, CompileRun(
4216 "o3_mirror.propertyNames().length")->Int32Value());
4217 CHECK_EQ(0, CompileRun(
4218 "o0_mirror.property('x').value().value()")->Int32Value());
4219 CHECK_EQ(1, CompileRun(
4220 "o0_mirror.property('y').value().value()")->Int32Value());
4221 CHECK_EQ(2, CompileRun(
4222 "o0_mirror.property('z').value().value()")->Int32Value());
4223 CHECK(CompileRun("o0_mirror.property('u').isUndefined()")->BooleanValue());
4224
4225 // The prototype (__proto__) for o0 should be o3 as o1 and o2 are hidden.
4226 CHECK(CompileRun("o0_mirror.protoObject() == o3_mirror")->BooleanValue());
4227}
4228
4229
4230static v8::Handle<v8::Value> ProtperyXNativeGetter(
4231 v8::Local<v8::String> property, const v8::AccessorInfo& info) {
4232 return v8::Integer::New(10);
4233}
4234
4235
4236TEST(NativeGetterPropertyMirror) {
4237 // Create a V8 environment with debug access.
4238 v8::HandleScope scope;
4239 DebugLocalContext env;
4240 env.ExposeDebug();
4241
4242 v8::Handle<v8::String> name = v8::String::New("x");
4243 // Create object with named accessor.
4244 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
4245 named->SetAccessor(name, &ProtperyXNativeGetter, NULL,
4246 v8::Handle<v8::Value>(), v8::DEFAULT, v8::None);
4247
4248 // Create object with named property getter.
4249 env->Global()->Set(v8::String::New("instance"), named->NewInstance());
4250 CHECK_EQ(10, CompileRun("instance.x")->Int32Value());
4251
4252 // Get mirror for the object with property getter.
4253 CompileRun("instance_mirror = debug.MakeMirror(instance);");
4254 CHECK(CompileRun(
4255 "instance_mirror instanceof debug.ObjectMirror")->BooleanValue());
4256
4257 CompileRun("named_names = instance_mirror.propertyNames();");
4258 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
4259 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue());
4260 CHECK(CompileRun(
4261 "instance_mirror.property('x').value().isNumber()")->BooleanValue());
4262 CHECK(CompileRun(
4263 "instance_mirror.property('x').value().value() == 10")->BooleanValue());
4264}
4265
4266
4267static v8::Handle<v8::Value> ProtperyXNativeGetterThrowingError(
4268 v8::Local<v8::String> property, const v8::AccessorInfo& info) {
4269 return CompileRun("throw new Error('Error message');");
4270}
4271
4272
4273TEST(NativeGetterThrowingErrorPropertyMirror) {
4274 // Create a V8 environment with debug access.
4275 v8::HandleScope scope;
4276 DebugLocalContext env;
4277 env.ExposeDebug();
4278
4279 v8::Handle<v8::String> name = v8::String::New("x");
4280 // Create object with named accessor.
4281 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
4282 named->SetAccessor(name, &ProtperyXNativeGetterThrowingError, NULL,
4283 v8::Handle<v8::Value>(), v8::DEFAULT, v8::None);
4284
4285 // Create object with named property getter.
4286 env->Global()->Set(v8::String::New("instance"), named->NewInstance());
4287
4288 // Get mirror for the object with property getter.
4289 CompileRun("instance_mirror = debug.MakeMirror(instance);");
4290 CHECK(CompileRun(
4291 "instance_mirror instanceof debug.ObjectMirror")->BooleanValue());
4292 CompileRun("named_names = instance_mirror.propertyNames();");
4293 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
4294 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue());
4295 CHECK(CompileRun(
4296 "instance_mirror.property('x').value().isError()")->BooleanValue());
4297
4298 // Check that the message is that passed to the Error constructor.
4299 CHECK(CompileRun(
4300 "instance_mirror.property('x').value().message() == 'Error message'")->
4301 BooleanValue());
4302}
4303
4304
Steve Blockd0582a62009-12-15 09:54:21 +00004305// Test that hidden properties object is not returned as an unnamed property
4306// among regular properties.
4307// See http://crbug.com/26491
4308TEST(NoHiddenProperties) {
4309 // Create a V8 environment with debug access.
4310 v8::HandleScope scope;
4311 DebugLocalContext env;
4312 env.ExposeDebug();
4313
4314 // Create an object in the global scope.
4315 const char* source = "var obj = {a: 1};";
4316 v8::Script::Compile(v8::String::New(source))->Run();
4317 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
4318 env->Global()->Get(v8::String::New("obj")));
4319 // Set a hidden property on the object.
4320 obj->SetHiddenValue(v8::String::New("v8::test-debug::a"),
4321 v8::Int32::New(11));
4322
4323 // Get mirror for the object with property getter.
4324 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
4325 CHECK(CompileRun(
4326 "obj_mirror instanceof debug.ObjectMirror")->BooleanValue());
4327 CompileRun("var named_names = obj_mirror.propertyNames();");
4328 // There should be exactly one property. But there is also an unnamed
4329 // property whose value is hidden properties dictionary. The latter
4330 // property should not be in the list of reguar properties.
4331 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
4332 CHECK(CompileRun("named_names[0] == 'a'")->BooleanValue());
4333 CHECK(CompileRun(
4334 "obj_mirror.property('a').value().value() == 1")->BooleanValue());
4335
4336 // Object created by t0 will become hidden prototype of object 'obj'.
4337 v8::Handle<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
4338 t0->InstanceTemplate()->Set(v8::String::New("b"), v8::Number::New(2));
4339 t0->SetHiddenPrototype(true);
4340 v8::Handle<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
4341 t1->InstanceTemplate()->Set(v8::String::New("c"), v8::Number::New(3));
4342
4343 // Create proto objects, add hidden properties to them and set them on
4344 // the global object.
4345 v8::Handle<v8::Object> protoObj = t0->GetFunction()->NewInstance();
4346 protoObj->SetHiddenValue(v8::String::New("v8::test-debug::b"),
4347 v8::Int32::New(12));
4348 env->Global()->Set(v8::String::New("protoObj"), protoObj);
4349 v8::Handle<v8::Object> grandProtoObj = t1->GetFunction()->NewInstance();
4350 grandProtoObj->SetHiddenValue(v8::String::New("v8::test-debug::c"),
4351 v8::Int32::New(13));
4352 env->Global()->Set(v8::String::New("grandProtoObj"), grandProtoObj);
4353
4354 // Setting prototypes: obj->protoObj->grandProtoObj
4355 protoObj->Set(v8::String::New("__proto__"), grandProtoObj);
4356 obj->Set(v8::String::New("__proto__"), protoObj);
4357
4358 // Get mirror for the object with property getter.
4359 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
4360 CHECK(CompileRun(
4361 "obj_mirror instanceof debug.ObjectMirror")->BooleanValue());
4362 CompileRun("var named_names = obj_mirror.propertyNames();");
4363 // There should be exactly two properties - one from the object itself and
4364 // another from its hidden prototype.
4365 CHECK_EQ(2, CompileRun("named_names.length")->Int32Value());
4366 CHECK(CompileRun("named_names.sort(); named_names[0] == 'a' &&"
4367 "named_names[1] == 'b'")->BooleanValue());
4368 CHECK(CompileRun(
4369 "obj_mirror.property('a').value().value() == 1")->BooleanValue());
4370 CHECK(CompileRun(
4371 "obj_mirror.property('b').value().value() == 2")->BooleanValue());
4372}
4373
Steve Blocka7e24c12009-10-30 11:49:00 +00004374
4375// Multithreaded tests of JSON debugger protocol
4376
4377// Support classes
4378
Steve Blocka7e24c12009-10-30 11:49:00 +00004379// Provides synchronization between k threads, where k is an input to the
4380// constructor. The Wait() call blocks a thread until it is called for the
4381// k'th time, then all calls return. Each ThreadBarrier object can only
4382// be used once.
4383class ThreadBarrier {
4384 public:
4385 explicit ThreadBarrier(int num_threads);
4386 ~ThreadBarrier();
4387 void Wait();
4388 private:
4389 int num_threads_;
4390 int num_blocked_;
4391 v8::internal::Mutex* lock_;
4392 v8::internal::Semaphore* sem_;
4393 bool invalid_;
4394};
4395
4396ThreadBarrier::ThreadBarrier(int num_threads)
4397 : num_threads_(num_threads), num_blocked_(0) {
4398 lock_ = OS::CreateMutex();
4399 sem_ = OS::CreateSemaphore(0);
4400 invalid_ = false; // A barrier may only be used once. Then it is invalid.
4401}
4402
4403// Do not call, due to race condition with Wait().
4404// Could be resolved with Pthread condition variables.
4405ThreadBarrier::~ThreadBarrier() {
4406 lock_->Lock();
4407 delete lock_;
4408 delete sem_;
4409}
4410
4411void ThreadBarrier::Wait() {
4412 lock_->Lock();
4413 CHECK(!invalid_);
4414 if (num_blocked_ == num_threads_ - 1) {
4415 // Signal and unblock all waiting threads.
4416 for (int i = 0; i < num_threads_ - 1; ++i) {
4417 sem_->Signal();
4418 }
4419 invalid_ = true;
4420 printf("BARRIER\n\n");
4421 fflush(stdout);
4422 lock_->Unlock();
4423 } else { // Wait for the semaphore.
4424 ++num_blocked_;
4425 lock_->Unlock(); // Potential race condition with destructor because
4426 sem_->Wait(); // these two lines are not atomic.
4427 }
4428}
4429
4430// A set containing enough barriers and semaphores for any of the tests.
4431class Barriers {
4432 public:
4433 Barriers();
4434 void Initialize();
4435 ThreadBarrier barrier_1;
4436 ThreadBarrier barrier_2;
4437 ThreadBarrier barrier_3;
4438 ThreadBarrier barrier_4;
4439 ThreadBarrier barrier_5;
4440 v8::internal::Semaphore* semaphore_1;
4441 v8::internal::Semaphore* semaphore_2;
4442};
4443
4444Barriers::Barriers() : barrier_1(2), barrier_2(2),
4445 barrier_3(2), barrier_4(2), barrier_5(2) {}
4446
4447void Barriers::Initialize() {
4448 semaphore_1 = OS::CreateSemaphore(0);
4449 semaphore_2 = OS::CreateSemaphore(0);
4450}
4451
4452
4453// We match parts of the message to decide if it is a break message.
4454bool IsBreakEventMessage(char *message) {
4455 const char* type_event = "\"type\":\"event\"";
4456 const char* event_break = "\"event\":\"break\"";
4457 // Does the message contain both type:event and event:break?
4458 return strstr(message, type_event) != NULL &&
4459 strstr(message, event_break) != NULL;
4460}
4461
4462
Steve Block3ce2e202009-11-05 08:53:23 +00004463// We match parts of the message to decide if it is a exception message.
4464bool IsExceptionEventMessage(char *message) {
4465 const char* type_event = "\"type\":\"event\"";
4466 const char* event_exception = "\"event\":\"exception\"";
4467 // Does the message contain both type:event and event:exception?
4468 return strstr(message, type_event) != NULL &&
4469 strstr(message, event_exception) != NULL;
4470}
4471
4472
4473// We match the message wether it is an evaluate response message.
4474bool IsEvaluateResponseMessage(char* message) {
4475 const char* type_response = "\"type\":\"response\"";
4476 const char* command_evaluate = "\"command\":\"evaluate\"";
4477 // Does the message contain both type:response and command:evaluate?
4478 return strstr(message, type_response) != NULL &&
4479 strstr(message, command_evaluate) != NULL;
4480}
4481
4482
Andrei Popescu402d9372010-02-26 13:31:12 +00004483static int StringToInt(const char* s) {
4484 return atoi(s); // NOLINT
4485}
4486
4487
Steve Block3ce2e202009-11-05 08:53:23 +00004488// We match parts of the message to get evaluate result int value.
4489int GetEvaluateIntResult(char *message) {
4490 const char* value = "\"value\":";
4491 char* pos = strstr(message, value);
4492 if (pos == NULL) {
4493 return -1;
4494 }
4495 int res = -1;
Andrei Popescu402d9372010-02-26 13:31:12 +00004496 res = StringToInt(pos + strlen(value));
Steve Block3ce2e202009-11-05 08:53:23 +00004497 return res;
4498}
4499
4500
4501// We match parts of the message to get hit breakpoint id.
4502int GetBreakpointIdFromBreakEventMessage(char *message) {
4503 const char* breakpoints = "\"breakpoints\":[";
4504 char* pos = strstr(message, breakpoints);
4505 if (pos == NULL) {
4506 return -1;
4507 }
4508 int res = -1;
Andrei Popescu402d9372010-02-26 13:31:12 +00004509 res = StringToInt(pos + strlen(breakpoints));
Steve Block3ce2e202009-11-05 08:53:23 +00004510 return res;
4511}
4512
4513
Leon Clarked91b9f72010-01-27 17:25:45 +00004514// We match parts of the message to get total frames number.
4515int GetTotalFramesInt(char *message) {
4516 const char* prefix = "\"totalFrames\":";
4517 char* pos = strstr(message, prefix);
4518 if (pos == NULL) {
4519 return -1;
4520 }
4521 pos += strlen(prefix);
Andrei Popescu402d9372010-02-26 13:31:12 +00004522 int res = StringToInt(pos);
Leon Clarked91b9f72010-01-27 17:25:45 +00004523 return res;
4524}
4525
4526
Steve Blocka7e24c12009-10-30 11:49:00 +00004527/* Test MessageQueues */
4528/* Tests the message queues that hold debugger commands and
4529 * response messages to the debugger. Fills queues and makes
4530 * them grow.
4531 */
4532Barriers message_queue_barriers;
4533
4534// This is the debugger thread, that executes no v8 calls except
4535// placing JSON debugger commands in the queue.
4536class MessageQueueDebuggerThread : public v8::internal::Thread {
4537 public:
4538 void Run();
4539};
4540
4541static void MessageHandler(const uint16_t* message, int length,
4542 v8::Debug::ClientData* client_data) {
4543 static char print_buffer[1000];
4544 Utf16ToAscii(message, length, print_buffer);
4545 if (IsBreakEventMessage(print_buffer)) {
4546 // Lets test script wait until break occurs to send commands.
4547 // Signals when a break is reported.
4548 message_queue_barriers.semaphore_2->Signal();
4549 }
4550
4551 // Allow message handler to block on a semaphore, to test queueing of
4552 // messages while blocked.
4553 message_queue_barriers.semaphore_1->Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +00004554}
4555
4556void MessageQueueDebuggerThread::Run() {
4557 const int kBufferSize = 1000;
4558 uint16_t buffer_1[kBufferSize];
4559 uint16_t buffer_2[kBufferSize];
4560 const char* command_1 =
4561 "{\"seq\":117,"
4562 "\"type\":\"request\","
4563 "\"command\":\"evaluate\","
4564 "\"arguments\":{\"expression\":\"1+2\"}}";
4565 const char* command_2 =
4566 "{\"seq\":118,"
4567 "\"type\":\"request\","
4568 "\"command\":\"evaluate\","
4569 "\"arguments\":{\"expression\":\"1+a\"}}";
4570 const char* command_3 =
4571 "{\"seq\":119,"
4572 "\"type\":\"request\","
4573 "\"command\":\"evaluate\","
4574 "\"arguments\":{\"expression\":\"c.d * b\"}}";
4575 const char* command_continue =
4576 "{\"seq\":106,"
4577 "\"type\":\"request\","
4578 "\"command\":\"continue\"}";
4579 const char* command_single_step =
4580 "{\"seq\":107,"
4581 "\"type\":\"request\","
4582 "\"command\":\"continue\","
4583 "\"arguments\":{\"stepaction\":\"next\"}}";
4584
4585 /* Interleaved sequence of actions by the two threads:*/
4586 // Main thread compiles and runs source_1
4587 message_queue_barriers.semaphore_1->Signal();
4588 message_queue_barriers.barrier_1.Wait();
4589 // Post 6 commands, filling the command queue and making it expand.
4590 // These calls return immediately, but the commands stay on the queue
4591 // until the execution of source_2.
4592 // Note: AsciiToUtf16 executes before SendCommand, so command is copied
4593 // to buffer before buffer is sent to SendCommand.
4594 v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_1, buffer_1));
4595 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_2, buffer_2));
4596 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
4597 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
4598 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
4599 message_queue_barriers.barrier_2.Wait();
4600 // Main thread compiles and runs source_2.
4601 // Queued commands are executed at the start of compilation of source_2(
4602 // beforeCompile event).
4603 // Free the message handler to process all the messages from the queue. 7
4604 // messages are expected: 2 afterCompile events and 5 responses.
4605 // All the commands added so far will fail to execute as long as call stack
4606 // is empty on beforeCompile event.
4607 for (int i = 0; i < 6 ; ++i) {
4608 message_queue_barriers.semaphore_1->Signal();
4609 }
4610 message_queue_barriers.barrier_3.Wait();
4611 // Main thread compiles and runs source_3.
4612 // Don't stop in the afterCompile handler.
4613 message_queue_barriers.semaphore_1->Signal();
4614 // source_3 includes a debugger statement, which causes a break event.
4615 // Wait on break event from hitting "debugger" statement
4616 message_queue_barriers.semaphore_2->Wait();
4617 // These should execute after the "debugger" statement in source_2
4618 v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_1, buffer_1));
4619 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_2, buffer_2));
4620 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
4621 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_single_step, buffer_2));
4622 // Run after 2 break events, 4 responses.
4623 for (int i = 0; i < 6 ; ++i) {
4624 message_queue_barriers.semaphore_1->Signal();
4625 }
4626 // Wait on break event after a single step executes.
4627 message_queue_barriers.semaphore_2->Wait();
4628 v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_2, buffer_1));
4629 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_continue, buffer_2));
4630 // Run after 2 responses.
4631 for (int i = 0; i < 2 ; ++i) {
4632 message_queue_barriers.semaphore_1->Signal();
4633 }
4634 // Main thread continues running source_3 to end, waits for this thread.
4635}
4636
4637MessageQueueDebuggerThread message_queue_debugger_thread;
4638
4639// This thread runs the v8 engine.
4640TEST(MessageQueues) {
4641 // Create a V8 environment
4642 v8::HandleScope scope;
4643 DebugLocalContext env;
4644 message_queue_barriers.Initialize();
4645 v8::Debug::SetMessageHandler(MessageHandler);
4646 message_queue_debugger_thread.Start();
4647
4648 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
4649 const char* source_2 = "e = 17;";
4650 const char* source_3 = "a = 4; debugger; a = 5; a = 6; a = 7;";
4651
4652 // See MessageQueueDebuggerThread::Run for interleaved sequence of
4653 // API calls and events in the two threads.
4654 CompileRun(source_1);
4655 message_queue_barriers.barrier_1.Wait();
4656 message_queue_barriers.barrier_2.Wait();
4657 CompileRun(source_2);
4658 message_queue_barriers.barrier_3.Wait();
4659 CompileRun(source_3);
4660 message_queue_debugger_thread.Join();
4661 fflush(stdout);
4662}
4663
4664
4665class TestClientData : public v8::Debug::ClientData {
4666 public:
4667 TestClientData() {
4668 constructor_call_counter++;
4669 }
4670 virtual ~TestClientData() {
4671 destructor_call_counter++;
4672 }
4673
4674 static void ResetCounters() {
4675 constructor_call_counter = 0;
4676 destructor_call_counter = 0;
4677 }
4678
4679 static int constructor_call_counter;
4680 static int destructor_call_counter;
4681};
4682
4683int TestClientData::constructor_call_counter = 0;
4684int TestClientData::destructor_call_counter = 0;
4685
4686
4687// Tests that MessageQueue doesn't destroy client data when expands and
4688// does destroy when it dies.
4689TEST(MessageQueueExpandAndDestroy) {
4690 TestClientData::ResetCounters();
4691 { // Create a scope for the queue.
4692 CommandMessageQueue queue(1);
4693 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4694 new TestClientData()));
4695 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4696 new TestClientData()));
4697 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4698 new TestClientData()));
4699 CHECK_EQ(0, TestClientData::destructor_call_counter);
4700 queue.Get().Dispose();
4701 CHECK_EQ(1, TestClientData::destructor_call_counter);
4702 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4703 new TestClientData()));
4704 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4705 new TestClientData()));
4706 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4707 new TestClientData()));
4708 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4709 new TestClientData()));
4710 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4711 new TestClientData()));
4712 CHECK_EQ(1, TestClientData::destructor_call_counter);
4713 queue.Get().Dispose();
4714 CHECK_EQ(2, TestClientData::destructor_call_counter);
4715 }
4716 // All the client data should be destroyed when the queue is destroyed.
4717 CHECK_EQ(TestClientData::destructor_call_counter,
4718 TestClientData::destructor_call_counter);
4719}
4720
4721
4722static int handled_client_data_instances_count = 0;
4723static void MessageHandlerCountingClientData(
4724 const v8::Debug::Message& message) {
4725 if (message.GetClientData() != NULL) {
4726 handled_client_data_instances_count++;
4727 }
4728}
4729
4730
4731// Tests that all client data passed to the debugger are sent to the handler.
4732TEST(SendClientDataToHandler) {
4733 // Create a V8 environment
4734 v8::HandleScope scope;
4735 DebugLocalContext env;
4736 TestClientData::ResetCounters();
4737 handled_client_data_instances_count = 0;
4738 v8::Debug::SetMessageHandler2(MessageHandlerCountingClientData);
4739 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
4740 const int kBufferSize = 1000;
4741 uint16_t buffer[kBufferSize];
4742 const char* command_1 =
4743 "{\"seq\":117,"
4744 "\"type\":\"request\","
4745 "\"command\":\"evaluate\","
4746 "\"arguments\":{\"expression\":\"1+2\"}}";
4747 const char* command_2 =
4748 "{\"seq\":118,"
4749 "\"type\":\"request\","
4750 "\"command\":\"evaluate\","
4751 "\"arguments\":{\"expression\":\"1+a\"}}";
4752 const char* command_continue =
4753 "{\"seq\":106,"
4754 "\"type\":\"request\","
4755 "\"command\":\"continue\"}";
4756
4757 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer),
4758 new TestClientData());
4759 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer), NULL);
4760 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer),
4761 new TestClientData());
4762 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer),
4763 new TestClientData());
4764 // All the messages will be processed on beforeCompile event.
4765 CompileRun(source_1);
4766 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer));
4767 CHECK_EQ(3, TestClientData::constructor_call_counter);
4768 CHECK_EQ(TestClientData::constructor_call_counter,
4769 handled_client_data_instances_count);
4770 CHECK_EQ(TestClientData::constructor_call_counter,
4771 TestClientData::destructor_call_counter);
4772}
4773
4774
4775/* Test ThreadedDebugging */
4776/* This test interrupts a running infinite loop that is
4777 * occupying the v8 thread by a break command from the
4778 * debugger thread. It then changes the value of a
4779 * global object, to make the loop terminate.
4780 */
4781
4782Barriers threaded_debugging_barriers;
4783
4784class V8Thread : public v8::internal::Thread {
4785 public:
4786 void Run();
4787};
4788
4789class DebuggerThread : public v8::internal::Thread {
4790 public:
4791 void Run();
4792};
4793
4794
4795static v8::Handle<v8::Value> ThreadedAtBarrier1(const v8::Arguments& args) {
4796 threaded_debugging_barriers.barrier_1.Wait();
4797 return v8::Undefined();
4798}
4799
4800
4801static void ThreadedMessageHandler(const v8::Debug::Message& message) {
4802 static char print_buffer[1000];
4803 v8::String::Value json(message.GetJSON());
4804 Utf16ToAscii(*json, json.length(), print_buffer);
4805 if (IsBreakEventMessage(print_buffer)) {
4806 threaded_debugging_barriers.barrier_2.Wait();
4807 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004808}
4809
4810
4811void V8Thread::Run() {
4812 const char* source =
4813 "flag = true;\n"
4814 "function bar( new_value ) {\n"
4815 " flag = new_value;\n"
4816 " return \"Return from bar(\" + new_value + \")\";\n"
4817 "}\n"
4818 "\n"
4819 "function foo() {\n"
4820 " var x = 1;\n"
4821 " while ( flag == true ) {\n"
4822 " if ( x == 1 ) {\n"
4823 " ThreadedAtBarrier1();\n"
4824 " }\n"
4825 " x = x + 1;\n"
4826 " }\n"
4827 "}\n"
4828 "\n"
4829 "foo();\n";
4830
4831 v8::HandleScope scope;
4832 DebugLocalContext env;
4833 v8::Debug::SetMessageHandler2(&ThreadedMessageHandler);
4834 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4835 global_template->Set(v8::String::New("ThreadedAtBarrier1"),
4836 v8::FunctionTemplate::New(ThreadedAtBarrier1));
4837 v8::Handle<v8::Context> context = v8::Context::New(NULL, global_template);
4838 v8::Context::Scope context_scope(context);
4839
4840 CompileRun(source);
4841}
4842
4843void DebuggerThread::Run() {
4844 const int kBufSize = 1000;
4845 uint16_t buffer[kBufSize];
4846
4847 const char* command_1 = "{\"seq\":102,"
4848 "\"type\":\"request\","
4849 "\"command\":\"evaluate\","
4850 "\"arguments\":{\"expression\":\"bar(false)\"}}";
4851 const char* command_2 = "{\"seq\":103,"
4852 "\"type\":\"request\","
4853 "\"command\":\"continue\"}";
4854
4855 threaded_debugging_barriers.barrier_1.Wait();
4856 v8::Debug::DebugBreak();
4857 threaded_debugging_barriers.barrier_2.Wait();
4858 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
4859 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
4860}
4861
4862DebuggerThread debugger_thread;
4863V8Thread v8_thread;
4864
4865TEST(ThreadedDebugging) {
4866 // Create a V8 environment
4867 threaded_debugging_barriers.Initialize();
4868
4869 v8_thread.Start();
4870 debugger_thread.Start();
4871
4872 v8_thread.Join();
4873 debugger_thread.Join();
4874}
4875
4876/* Test RecursiveBreakpoints */
4877/* In this test, the debugger evaluates a function with a breakpoint, after
4878 * hitting a breakpoint in another function. We do this with both values
4879 * of the flag enabling recursive breakpoints, and verify that the second
4880 * breakpoint is hit when enabled, and missed when disabled.
4881 */
4882
4883class BreakpointsV8Thread : public v8::internal::Thread {
4884 public:
4885 void Run();
4886};
4887
4888class BreakpointsDebuggerThread : public v8::internal::Thread {
4889 public:
Leon Clarked91b9f72010-01-27 17:25:45 +00004890 explicit BreakpointsDebuggerThread(bool global_evaluate)
4891 : global_evaluate_(global_evaluate) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00004892 void Run();
Leon Clarked91b9f72010-01-27 17:25:45 +00004893
4894 private:
4895 bool global_evaluate_;
Steve Blocka7e24c12009-10-30 11:49:00 +00004896};
4897
4898
4899Barriers* breakpoints_barriers;
Steve Block3ce2e202009-11-05 08:53:23 +00004900int break_event_breakpoint_id;
4901int evaluate_int_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00004902
4903static void BreakpointsMessageHandler(const v8::Debug::Message& message) {
4904 static char print_buffer[1000];
4905 v8::String::Value json(message.GetJSON());
4906 Utf16ToAscii(*json, json.length(), print_buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00004907
Steve Blocka7e24c12009-10-30 11:49:00 +00004908 if (IsBreakEventMessage(print_buffer)) {
Steve Block3ce2e202009-11-05 08:53:23 +00004909 break_event_breakpoint_id =
4910 GetBreakpointIdFromBreakEventMessage(print_buffer);
4911 breakpoints_barriers->semaphore_1->Signal();
4912 } else if (IsEvaluateResponseMessage(print_buffer)) {
4913 evaluate_int_result = GetEvaluateIntResult(print_buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00004914 breakpoints_barriers->semaphore_1->Signal();
4915 }
4916}
4917
4918
4919void BreakpointsV8Thread::Run() {
4920 const char* source_1 = "var y_global = 3;\n"
4921 "function cat( new_value ) {\n"
4922 " var x = new_value;\n"
Steve Block3ce2e202009-11-05 08:53:23 +00004923 " y_global = y_global + 4;\n"
Steve Blocka7e24c12009-10-30 11:49:00 +00004924 " x = 3 * x + 1;\n"
Steve Block3ce2e202009-11-05 08:53:23 +00004925 " y_global = y_global + 5;\n"
Steve Blocka7e24c12009-10-30 11:49:00 +00004926 " return x;\n"
4927 "}\n"
4928 "\n"
4929 "function dog() {\n"
4930 " var x = 1;\n"
4931 " x = y_global;"
4932 " var z = 3;"
4933 " x += 100;\n"
4934 " return x;\n"
4935 "}\n"
4936 "\n";
4937 const char* source_2 = "cat(17);\n"
4938 "cat(19);\n";
4939
4940 v8::HandleScope scope;
4941 DebugLocalContext env;
4942 v8::Debug::SetMessageHandler2(&BreakpointsMessageHandler);
4943
4944 CompileRun(source_1);
4945 breakpoints_barriers->barrier_1.Wait();
4946 breakpoints_barriers->barrier_2.Wait();
4947 CompileRun(source_2);
4948}
4949
4950
4951void BreakpointsDebuggerThread::Run() {
4952 const int kBufSize = 1000;
4953 uint16_t buffer[kBufSize];
4954
4955 const char* command_1 = "{\"seq\":101,"
4956 "\"type\":\"request\","
4957 "\"command\":\"setbreakpoint\","
4958 "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}";
4959 const char* command_2 = "{\"seq\":102,"
4960 "\"type\":\"request\","
4961 "\"command\":\"setbreakpoint\","
4962 "\"arguments\":{\"type\":\"function\",\"target\":\"dog\",\"line\":3}}";
Leon Clarked91b9f72010-01-27 17:25:45 +00004963 const char* command_3;
4964 if (this->global_evaluate_) {
4965 command_3 = "{\"seq\":103,"
4966 "\"type\":\"request\","
4967 "\"command\":\"evaluate\","
4968 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false,"
4969 "\"global\":true}}";
4970 } else {
4971 command_3 = "{\"seq\":103,"
4972 "\"type\":\"request\","
4973 "\"command\":\"evaluate\","
4974 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false}}";
4975 }
4976 const char* command_4;
4977 if (this->global_evaluate_) {
4978 command_4 = "{\"seq\":104,"
4979 "\"type\":\"request\","
4980 "\"command\":\"evaluate\","
4981 "\"arguments\":{\"expression\":\"100 + 8\",\"disable_break\":true,"
4982 "\"global\":true}}";
4983 } else {
4984 command_4 = "{\"seq\":104,"
4985 "\"type\":\"request\","
4986 "\"command\":\"evaluate\","
4987 "\"arguments\":{\"expression\":\"x + 1\",\"disable_break\":true}}";
4988 }
Steve Block3ce2e202009-11-05 08:53:23 +00004989 const char* command_5 = "{\"seq\":105,"
Steve Blocka7e24c12009-10-30 11:49:00 +00004990 "\"type\":\"request\","
4991 "\"command\":\"continue\"}";
Steve Block3ce2e202009-11-05 08:53:23 +00004992 const char* command_6 = "{\"seq\":106,"
Steve Blocka7e24c12009-10-30 11:49:00 +00004993 "\"type\":\"request\","
4994 "\"command\":\"continue\"}";
Leon Clarked91b9f72010-01-27 17:25:45 +00004995 const char* command_7;
4996 if (this->global_evaluate_) {
4997 command_7 = "{\"seq\":107,"
4998 "\"type\":\"request\","
4999 "\"command\":\"evaluate\","
5000 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true,"
5001 "\"global\":true}}";
5002 } else {
5003 command_7 = "{\"seq\":107,"
5004 "\"type\":\"request\","
5005 "\"command\":\"evaluate\","
5006 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true}}";
5007 }
Steve Block3ce2e202009-11-05 08:53:23 +00005008 const char* command_8 = "{\"seq\":108,"
Steve Blocka7e24c12009-10-30 11:49:00 +00005009 "\"type\":\"request\","
5010 "\"command\":\"continue\"}";
5011
5012
5013 // v8 thread initializes, runs source_1
5014 breakpoints_barriers->barrier_1.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005015 // 1:Set breakpoint in cat() (will get id 1).
Steve Blocka7e24c12009-10-30 11:49:00 +00005016 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005017 // 2:Set breakpoint in dog() (will get id 2).
Steve Blocka7e24c12009-10-30 11:49:00 +00005018 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
5019 breakpoints_barriers->barrier_2.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005020 // V8 thread starts compiling source_2.
Steve Blocka7e24c12009-10-30 11:49:00 +00005021 // Automatic break happens, to run queued commands
5022 // breakpoints_barriers->semaphore_1->Wait();
5023 // Commands 1 through 3 run, thread continues.
5024 // v8 thread runs source_2 to breakpoint in cat().
5025 // message callback receives break event.
5026 breakpoints_barriers->semaphore_1->Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005027 // Must have hit breakpoint #1.
5028 CHECK_EQ(1, break_event_breakpoint_id);
Steve Blocka7e24c12009-10-30 11:49:00 +00005029 // 4:Evaluate dog() (which has a breakpoint).
5030 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_3, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005031 // V8 thread hits breakpoint in dog().
Steve Blocka7e24c12009-10-30 11:49:00 +00005032 breakpoints_barriers->semaphore_1->Wait(); // wait for break event
Steve Block3ce2e202009-11-05 08:53:23 +00005033 // Must have hit breakpoint #2.
5034 CHECK_EQ(2, break_event_breakpoint_id);
5035 // 5:Evaluate (x + 1).
Steve Blocka7e24c12009-10-30 11:49:00 +00005036 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_4, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005037 // Evaluate (x + 1) finishes.
5038 breakpoints_barriers->semaphore_1->Wait();
5039 // Must have result 108.
5040 CHECK_EQ(108, evaluate_int_result);
5041 // 6:Continue evaluation of dog().
Steve Blocka7e24c12009-10-30 11:49:00 +00005042 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_5, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005043 // Evaluate dog() finishes.
5044 breakpoints_barriers->semaphore_1->Wait();
5045 // Must have result 107.
5046 CHECK_EQ(107, evaluate_int_result);
Steve Blocka7e24c12009-10-30 11:49:00 +00005047 // 7:Continue evaluation of source_2, finish cat(17), hit breakpoint
5048 // in cat(19).
5049 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_6, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005050 // Message callback gets break event.
Steve Blocka7e24c12009-10-30 11:49:00 +00005051 breakpoints_barriers->semaphore_1->Wait(); // wait for break event
Steve Block3ce2e202009-11-05 08:53:23 +00005052 // Must have hit breakpoint #1.
5053 CHECK_EQ(1, break_event_breakpoint_id);
5054 // 8: Evaluate dog() with breaks disabled.
Steve Blocka7e24c12009-10-30 11:49:00 +00005055 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_7, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005056 // Evaluate dog() finishes.
5057 breakpoints_barriers->semaphore_1->Wait();
5058 // Must have result 116.
5059 CHECK_EQ(116, evaluate_int_result);
Steve Blocka7e24c12009-10-30 11:49:00 +00005060 // 9: Continue evaluation of source2, reach end.
5061 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_8, buffer));
5062}
5063
Leon Clarked91b9f72010-01-27 17:25:45 +00005064void TestRecursiveBreakpointsGeneric(bool global_evaluate) {
Leon Clarkeeab96aa2010-01-27 16:31:12 +00005065 i::FLAG_debugger_auto_break = true;
Leon Clarke888f6722010-01-27 15:57:47 +00005066
Leon Clarked91b9f72010-01-27 17:25:45 +00005067 BreakpointsDebuggerThread breakpoints_debugger_thread(global_evaluate);
5068 BreakpointsV8Thread breakpoints_v8_thread;
5069
Steve Blocka7e24c12009-10-30 11:49:00 +00005070 // Create a V8 environment
5071 Barriers stack_allocated_breakpoints_barriers;
5072 stack_allocated_breakpoints_barriers.Initialize();
5073 breakpoints_barriers = &stack_allocated_breakpoints_barriers;
5074
5075 breakpoints_v8_thread.Start();
5076 breakpoints_debugger_thread.Start();
5077
5078 breakpoints_v8_thread.Join();
5079 breakpoints_debugger_thread.Join();
5080}
5081
Leon Clarked91b9f72010-01-27 17:25:45 +00005082TEST(RecursiveBreakpoints) {
5083 TestRecursiveBreakpointsGeneric(false);
5084}
5085
5086TEST(RecursiveBreakpointsGlobal) {
5087 TestRecursiveBreakpointsGeneric(true);
5088}
5089
Steve Blocka7e24c12009-10-30 11:49:00 +00005090
5091static void DummyDebugEventListener(v8::DebugEvent event,
5092 v8::Handle<v8::Object> exec_state,
5093 v8::Handle<v8::Object> event_data,
5094 v8::Handle<v8::Value> data) {
5095}
5096
5097
5098TEST(SetDebugEventListenerOnUninitializedVM) {
5099 v8::Debug::SetDebugEventListener(DummyDebugEventListener);
5100}
5101
5102
5103static void DummyMessageHandler(const v8::Debug::Message& message) {
5104}
5105
5106
5107TEST(SetMessageHandlerOnUninitializedVM) {
5108 v8::Debug::SetMessageHandler2(DummyMessageHandler);
5109}
5110
5111
5112TEST(DebugBreakOnUninitializedVM) {
5113 v8::Debug::DebugBreak();
5114}
5115
5116
5117TEST(SendCommandToUninitializedVM) {
5118 const char* dummy_command = "{}";
5119 uint16_t dummy_buffer[80];
5120 int dummy_length = AsciiToUtf16(dummy_command, dummy_buffer);
5121 v8::Debug::SendCommand(dummy_buffer, dummy_length);
5122}
5123
5124
5125// Source for a JavaScript function which returns the data parameter of a
5126// function called in the context of the debugger. If no data parameter is
5127// passed it throws an exception.
5128static const char* debugger_call_with_data_source =
5129 "function debugger_call_with_data(exec_state, data) {"
5130 " if (data) return data;"
5131 " throw 'No data!'"
5132 "}";
5133v8::Handle<v8::Function> debugger_call_with_data;
5134
5135
5136// Source for a JavaScript function which returns the data parameter of a
5137// function called in the context of the debugger. If no data parameter is
5138// passed it throws an exception.
5139static const char* debugger_call_with_closure_source =
5140 "var x = 3;"
5141 "(function (exec_state) {"
5142 " if (exec_state.y) return x - 1;"
5143 " exec_state.y = x;"
5144 " return exec_state.y"
5145 "})";
5146v8::Handle<v8::Function> debugger_call_with_closure;
5147
5148// Function to retrieve the number of JavaScript frames by calling a JavaScript
5149// in the debugger.
5150static v8::Handle<v8::Value> CheckFrameCount(const v8::Arguments& args) {
5151 CHECK(v8::Debug::Call(frame_count)->IsNumber());
5152 CHECK_EQ(args[0]->Int32Value(),
5153 v8::Debug::Call(frame_count)->Int32Value());
5154 return v8::Undefined();
5155}
5156
5157
5158// Function to retrieve the source line of the top JavaScript frame by calling a
5159// JavaScript function in the debugger.
5160static v8::Handle<v8::Value> CheckSourceLine(const v8::Arguments& args) {
5161 CHECK(v8::Debug::Call(frame_source_line)->IsNumber());
5162 CHECK_EQ(args[0]->Int32Value(),
5163 v8::Debug::Call(frame_source_line)->Int32Value());
5164 return v8::Undefined();
5165}
5166
5167
5168// Function to test passing an additional parameter to a JavaScript function
5169// called in the debugger. It also tests that functions called in the debugger
5170// can throw exceptions.
5171static v8::Handle<v8::Value> CheckDataParameter(const v8::Arguments& args) {
5172 v8::Handle<v8::String> data = v8::String::New("Test");
5173 CHECK(v8::Debug::Call(debugger_call_with_data, data)->IsString());
5174
5175 CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
5176 CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
5177
5178 v8::TryCatch catcher;
5179 v8::Debug::Call(debugger_call_with_data);
5180 CHECK(catcher.HasCaught());
5181 CHECK(catcher.Exception()->IsString());
5182
5183 return v8::Undefined();
5184}
5185
5186
5187// Function to test using a JavaScript with closure in the debugger.
5188static v8::Handle<v8::Value> CheckClosure(const v8::Arguments& args) {
5189 CHECK(v8::Debug::Call(debugger_call_with_closure)->IsNumber());
5190 CHECK_EQ(3, v8::Debug::Call(debugger_call_with_closure)->Int32Value());
5191 return v8::Undefined();
5192}
5193
5194
5195// Test functions called through the debugger.
5196TEST(CallFunctionInDebugger) {
5197 // Create and enter a context with the functions CheckFrameCount,
5198 // CheckSourceLine and CheckDataParameter installed.
5199 v8::HandleScope scope;
5200 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5201 global_template->Set(v8::String::New("CheckFrameCount"),
5202 v8::FunctionTemplate::New(CheckFrameCount));
5203 global_template->Set(v8::String::New("CheckSourceLine"),
5204 v8::FunctionTemplate::New(CheckSourceLine));
5205 global_template->Set(v8::String::New("CheckDataParameter"),
5206 v8::FunctionTemplate::New(CheckDataParameter));
5207 global_template->Set(v8::String::New("CheckClosure"),
5208 v8::FunctionTemplate::New(CheckClosure));
5209 v8::Handle<v8::Context> context = v8::Context::New(NULL, global_template);
5210 v8::Context::Scope context_scope(context);
5211
5212 // Compile a function for checking the number of JavaScript frames.
5213 v8::Script::Compile(v8::String::New(frame_count_source))->Run();
5214 frame_count = v8::Local<v8::Function>::Cast(
5215 context->Global()->Get(v8::String::New("frame_count")));
5216
5217 // Compile a function for returning the source line for the top frame.
5218 v8::Script::Compile(v8::String::New(frame_source_line_source))->Run();
5219 frame_source_line = v8::Local<v8::Function>::Cast(
5220 context->Global()->Get(v8::String::New("frame_source_line")));
5221
5222 // Compile a function returning the data parameter.
5223 v8::Script::Compile(v8::String::New(debugger_call_with_data_source))->Run();
5224 debugger_call_with_data = v8::Local<v8::Function>::Cast(
5225 context->Global()->Get(v8::String::New("debugger_call_with_data")));
5226
5227 // Compile a function capturing closure.
5228 debugger_call_with_closure = v8::Local<v8::Function>::Cast(
5229 v8::Script::Compile(
5230 v8::String::New(debugger_call_with_closure_source))->Run());
5231
Steve Block6ded16b2010-05-10 14:33:55 +01005232 // Calling a function through the debugger returns 0 frames if there are
5233 // no JavaScript frames.
5234 CHECK_EQ(v8::Integer::New(0), v8::Debug::Call(frame_count));
Steve Blocka7e24c12009-10-30 11:49:00 +00005235
5236 // Test that the number of frames can be retrieved.
5237 v8::Script::Compile(v8::String::New("CheckFrameCount(1)"))->Run();
5238 v8::Script::Compile(v8::String::New("function f() {"
5239 " CheckFrameCount(2);"
5240 "}; f()"))->Run();
5241
5242 // Test that the source line can be retrieved.
5243 v8::Script::Compile(v8::String::New("CheckSourceLine(0)"))->Run();
5244 v8::Script::Compile(v8::String::New("function f() {\n"
5245 " CheckSourceLine(1)\n"
5246 " CheckSourceLine(2)\n"
5247 " CheckSourceLine(3)\n"
5248 "}; f()"))->Run();
5249
5250 // Test that a parameter can be passed to a function called in the debugger.
5251 v8::Script::Compile(v8::String::New("CheckDataParameter()"))->Run();
5252
5253 // Test that a function with closure can be run in the debugger.
5254 v8::Script::Compile(v8::String::New("CheckClosure()"))->Run();
5255
5256
5257 // Test that the source line is correct when there is a line offset.
5258 v8::ScriptOrigin origin(v8::String::New("test"),
5259 v8::Integer::New(7));
5260 v8::Script::Compile(v8::String::New("CheckSourceLine(7)"), &origin)->Run();
5261 v8::Script::Compile(v8::String::New("function f() {\n"
5262 " CheckSourceLine(8)\n"
5263 " CheckSourceLine(9)\n"
5264 " CheckSourceLine(10)\n"
5265 "}; f()"), &origin)->Run();
5266}
5267
5268
5269// Debugger message handler which counts the number of breaks.
5270static void SendContinueCommand();
5271static void MessageHandlerBreakPointHitCount(
5272 const v8::Debug::Message& message) {
5273 if (message.IsEvent() && message.GetEvent() == v8::Break) {
5274 // Count the number of breaks.
5275 break_point_hit_count++;
5276
5277 SendContinueCommand();
5278 }
5279}
5280
5281
5282// Test that clearing the debug event listener actually clears all break points
5283// and related information.
5284TEST(DebuggerUnload) {
5285 DebugLocalContext env;
5286
5287 // Check debugger is unloaded before it is used.
5288 CheckDebuggerUnloaded();
5289
5290 // Set a debug event listener.
5291 break_point_hit_count = 0;
5292 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
5293 v8::Undefined());
5294 {
5295 v8::HandleScope scope;
5296 // Create a couple of functions for the test.
5297 v8::Local<v8::Function> foo =
5298 CompileFunction(&env, "function foo(){x=1}", "foo");
5299 v8::Local<v8::Function> bar =
5300 CompileFunction(&env, "function bar(){y=2}", "bar");
5301
5302 // Set some break points.
5303 SetBreakPoint(foo, 0);
5304 SetBreakPoint(foo, 4);
5305 SetBreakPoint(bar, 0);
5306 SetBreakPoint(bar, 4);
5307
5308 // Make sure that the break points are there.
5309 break_point_hit_count = 0;
5310 foo->Call(env->Global(), 0, NULL);
5311 CHECK_EQ(2, break_point_hit_count);
5312 bar->Call(env->Global(), 0, NULL);
5313 CHECK_EQ(4, break_point_hit_count);
5314 }
5315
5316 // Remove the debug event listener without clearing breakpoints. Do this
5317 // outside a handle scope.
5318 v8::Debug::SetDebugEventListener(NULL);
5319 CheckDebuggerUnloaded(true);
5320
5321 // Now set a debug message handler.
5322 break_point_hit_count = 0;
5323 v8::Debug::SetMessageHandler2(MessageHandlerBreakPointHitCount);
5324 {
5325 v8::HandleScope scope;
5326
5327 // Get the test functions again.
5328 v8::Local<v8::Function> foo =
5329 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
5330 v8::Local<v8::Function> bar =
5331 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
5332
5333 foo->Call(env->Global(), 0, NULL);
5334 CHECK_EQ(0, break_point_hit_count);
5335
5336 // Set break points and run again.
5337 SetBreakPoint(foo, 0);
5338 SetBreakPoint(foo, 4);
5339 foo->Call(env->Global(), 0, NULL);
5340 CHECK_EQ(2, break_point_hit_count);
5341 }
5342
5343 // Remove the debug message handler without clearing breakpoints. Do this
5344 // outside a handle scope.
5345 v8::Debug::SetMessageHandler2(NULL);
5346 CheckDebuggerUnloaded(true);
5347}
5348
5349
5350// Sends continue command to the debugger.
5351static void SendContinueCommand() {
5352 const int kBufferSize = 1000;
5353 uint16_t buffer[kBufferSize];
5354 const char* command_continue =
5355 "{\"seq\":0,"
5356 "\"type\":\"request\","
5357 "\"command\":\"continue\"}";
5358
5359 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer));
5360}
5361
5362
5363// Debugger message handler which counts the number of times it is called.
5364static int message_handler_hit_count = 0;
5365static void MessageHandlerHitCount(const v8::Debug::Message& message) {
5366 message_handler_hit_count++;
5367
Steve Block3ce2e202009-11-05 08:53:23 +00005368 static char print_buffer[1000];
5369 v8::String::Value json(message.GetJSON());
5370 Utf16ToAscii(*json, json.length(), print_buffer);
5371 if (IsExceptionEventMessage(print_buffer)) {
5372 // Send a continue command for exception events.
5373 SendContinueCommand();
5374 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005375}
5376
5377
5378// Test clearing the debug message handler.
5379TEST(DebuggerClearMessageHandler) {
5380 v8::HandleScope scope;
5381 DebugLocalContext env;
5382
5383 // Check debugger is unloaded before it is used.
5384 CheckDebuggerUnloaded();
5385
5386 // Set a debug message handler.
5387 v8::Debug::SetMessageHandler2(MessageHandlerHitCount);
5388
5389 // Run code to throw a unhandled exception. This should end up in the message
5390 // handler.
5391 CompileRun("throw 1");
5392
5393 // The message handler should be called.
5394 CHECK_GT(message_handler_hit_count, 0);
5395
5396 // Clear debug message handler.
5397 message_handler_hit_count = 0;
5398 v8::Debug::SetMessageHandler(NULL);
5399
5400 // Run code to throw a unhandled exception. This should end up in the message
5401 // handler.
5402 CompileRun("throw 1");
5403
5404 // The message handler should not be called more.
5405 CHECK_EQ(0, message_handler_hit_count);
5406
5407 CheckDebuggerUnloaded(true);
5408}
5409
5410
5411// Debugger message handler which clears the message handler while active.
5412static void MessageHandlerClearingMessageHandler(
5413 const v8::Debug::Message& message) {
5414 message_handler_hit_count++;
5415
5416 // Clear debug message handler.
5417 v8::Debug::SetMessageHandler(NULL);
5418}
5419
5420
5421// Test clearing the debug message handler while processing a debug event.
5422TEST(DebuggerClearMessageHandlerWhileActive) {
5423 v8::HandleScope scope;
5424 DebugLocalContext env;
5425
5426 // Check debugger is unloaded before it is used.
5427 CheckDebuggerUnloaded();
5428
5429 // Set a debug message handler.
5430 v8::Debug::SetMessageHandler2(MessageHandlerClearingMessageHandler);
5431
5432 // Run code to throw a unhandled exception. This should end up in the message
5433 // handler.
5434 CompileRun("throw 1");
5435
5436 // The message handler should be called.
5437 CHECK_EQ(1, message_handler_hit_count);
5438
5439 CheckDebuggerUnloaded(true);
5440}
5441
5442
5443/* Test DebuggerHostDispatch */
5444/* In this test, the debugger waits for a command on a breakpoint
5445 * and is dispatching host commands while in the infinite loop.
5446 */
5447
5448class HostDispatchV8Thread : public v8::internal::Thread {
5449 public:
5450 void Run();
5451};
5452
5453class HostDispatchDebuggerThread : public v8::internal::Thread {
5454 public:
5455 void Run();
5456};
5457
5458Barriers* host_dispatch_barriers;
5459
5460static void HostDispatchMessageHandler(const v8::Debug::Message& message) {
5461 static char print_buffer[1000];
5462 v8::String::Value json(message.GetJSON());
5463 Utf16ToAscii(*json, json.length(), print_buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00005464}
5465
5466
5467static void HostDispatchDispatchHandler() {
5468 host_dispatch_barriers->semaphore_1->Signal();
5469}
5470
5471
5472void HostDispatchV8Thread::Run() {
5473 const char* source_1 = "var y_global = 3;\n"
5474 "function cat( new_value ) {\n"
5475 " var x = new_value;\n"
5476 " y_global = 4;\n"
5477 " x = 3 * x + 1;\n"
5478 " y_global = 5;\n"
5479 " return x;\n"
5480 "}\n"
5481 "\n";
5482 const char* source_2 = "cat(17);\n";
5483
5484 v8::HandleScope scope;
5485 DebugLocalContext env;
5486
5487 // Setup message and host dispatch handlers.
5488 v8::Debug::SetMessageHandler2(HostDispatchMessageHandler);
5489 v8::Debug::SetHostDispatchHandler(HostDispatchDispatchHandler, 10 /* ms */);
5490
5491 CompileRun(source_1);
5492 host_dispatch_barriers->barrier_1.Wait();
5493 host_dispatch_barriers->barrier_2.Wait();
5494 CompileRun(source_2);
5495}
5496
5497
5498void HostDispatchDebuggerThread::Run() {
5499 const int kBufSize = 1000;
5500 uint16_t buffer[kBufSize];
5501
5502 const char* command_1 = "{\"seq\":101,"
5503 "\"type\":\"request\","
5504 "\"command\":\"setbreakpoint\","
5505 "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}";
5506 const char* command_2 = "{\"seq\":102,"
5507 "\"type\":\"request\","
5508 "\"command\":\"continue\"}";
5509
5510 // v8 thread initializes, runs source_1
5511 host_dispatch_barriers->barrier_1.Wait();
5512 // 1: Set breakpoint in cat().
5513 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
5514
5515 host_dispatch_barriers->barrier_2.Wait();
5516 // v8 thread starts compiling source_2.
5517 // Break happens, to run queued commands and host dispatches.
5518 // Wait for host dispatch to be processed.
5519 host_dispatch_barriers->semaphore_1->Wait();
5520 // 2: Continue evaluation
5521 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
5522}
5523
5524HostDispatchDebuggerThread host_dispatch_debugger_thread;
5525HostDispatchV8Thread host_dispatch_v8_thread;
5526
5527
5528TEST(DebuggerHostDispatch) {
5529 i::FLAG_debugger_auto_break = true;
5530
5531 // Create a V8 environment
5532 Barriers stack_allocated_host_dispatch_barriers;
5533 stack_allocated_host_dispatch_barriers.Initialize();
5534 host_dispatch_barriers = &stack_allocated_host_dispatch_barriers;
5535
5536 host_dispatch_v8_thread.Start();
5537 host_dispatch_debugger_thread.Start();
5538
5539 host_dispatch_v8_thread.Join();
5540 host_dispatch_debugger_thread.Join();
5541}
5542
5543
Steve Blockd0582a62009-12-15 09:54:21 +00005544/* Test DebugMessageDispatch */
5545/* In this test, the V8 thread waits for a message from the debug thread.
5546 * The DebugMessageDispatchHandler is executed from the debugger thread
5547 * which signals the V8 thread to wake up.
5548 */
5549
5550class DebugMessageDispatchV8Thread : public v8::internal::Thread {
5551 public:
5552 void Run();
5553};
5554
5555class DebugMessageDispatchDebuggerThread : public v8::internal::Thread {
5556 public:
5557 void Run();
5558};
5559
5560Barriers* debug_message_dispatch_barriers;
5561
5562
5563static void DebugMessageHandler() {
5564 debug_message_dispatch_barriers->semaphore_1->Signal();
5565}
5566
5567
5568void DebugMessageDispatchV8Thread::Run() {
5569 v8::HandleScope scope;
5570 DebugLocalContext env;
5571
5572 // Setup debug message dispatch handler.
5573 v8::Debug::SetDebugMessageDispatchHandler(DebugMessageHandler);
5574
5575 CompileRun("var y = 1 + 2;\n");
5576 debug_message_dispatch_barriers->barrier_1.Wait();
5577 debug_message_dispatch_barriers->semaphore_1->Wait();
5578 debug_message_dispatch_barriers->barrier_2.Wait();
5579}
5580
5581
5582void DebugMessageDispatchDebuggerThread::Run() {
5583 debug_message_dispatch_barriers->barrier_1.Wait();
5584 SendContinueCommand();
5585 debug_message_dispatch_barriers->barrier_2.Wait();
5586}
5587
5588DebugMessageDispatchDebuggerThread debug_message_dispatch_debugger_thread;
5589DebugMessageDispatchV8Thread debug_message_dispatch_v8_thread;
5590
5591
5592TEST(DebuggerDebugMessageDispatch) {
5593 i::FLAG_debugger_auto_break = true;
5594
5595 // Create a V8 environment
5596 Barriers stack_allocated_debug_message_dispatch_barriers;
5597 stack_allocated_debug_message_dispatch_barriers.Initialize();
5598 debug_message_dispatch_barriers =
5599 &stack_allocated_debug_message_dispatch_barriers;
5600
5601 debug_message_dispatch_v8_thread.Start();
5602 debug_message_dispatch_debugger_thread.Start();
5603
5604 debug_message_dispatch_v8_thread.Join();
5605 debug_message_dispatch_debugger_thread.Join();
5606}
5607
5608
Steve Blocka7e24c12009-10-30 11:49:00 +00005609TEST(DebuggerAgent) {
5610 // Make sure these ports is not used by other tests to allow tests to run in
5611 // parallel.
5612 const int kPort1 = 5858;
5613 const int kPort2 = 5857;
5614 const int kPort3 = 5856;
5615
5616 // Make a string with the port2 number.
5617 const int kPortBufferLen = 6;
5618 char port2_str[kPortBufferLen];
5619 OS::SNPrintF(i::Vector<char>(port2_str, kPortBufferLen), "%d", kPort2);
5620
5621 bool ok;
5622
5623 // Initialize the socket library.
5624 i::Socket::Setup();
5625
5626 // Test starting and stopping the agent without any client connection.
5627 i::Debugger::StartAgent("test", kPort1);
5628 i::Debugger::StopAgent();
5629
5630 // Test starting the agent, connecting a client and shutting down the agent
5631 // with the client connected.
5632 ok = i::Debugger::StartAgent("test", kPort2);
5633 CHECK(ok);
5634 i::Debugger::WaitForAgent();
5635 i::Socket* client = i::OS::CreateSocket();
5636 ok = client->Connect("localhost", port2_str);
5637 CHECK(ok);
5638 i::Debugger::StopAgent();
5639 delete client;
5640
5641 // Test starting and stopping the agent with the required port already
5642 // occoupied.
5643 i::Socket* server = i::OS::CreateSocket();
5644 server->Bind(kPort3);
5645
5646 i::Debugger::StartAgent("test", kPort3);
5647 i::Debugger::StopAgent();
5648
5649 delete server;
5650}
5651
5652
5653class DebuggerAgentProtocolServerThread : public i::Thread {
5654 public:
5655 explicit DebuggerAgentProtocolServerThread(int port)
5656 : port_(port), server_(NULL), client_(NULL),
5657 listening_(OS::CreateSemaphore(0)) {
5658 }
5659 ~DebuggerAgentProtocolServerThread() {
5660 // Close both sockets.
5661 delete client_;
5662 delete server_;
5663 delete listening_;
5664 }
5665
5666 void Run();
5667 void WaitForListening() { listening_->Wait(); }
5668 char* body() { return *body_; }
5669
5670 private:
5671 int port_;
5672 i::SmartPointer<char> body_;
5673 i::Socket* server_; // Server socket used for bind/accept.
5674 i::Socket* client_; // Single client connection used by the test.
5675 i::Semaphore* listening_; // Signalled when the server is in listen mode.
5676};
5677
5678
5679void DebuggerAgentProtocolServerThread::Run() {
5680 bool ok;
5681
5682 // Create the server socket and bind it to the requested port.
5683 server_ = i::OS::CreateSocket();
5684 CHECK(server_ != NULL);
5685 ok = server_->Bind(port_);
5686 CHECK(ok);
5687
5688 // Listen for new connections.
5689 ok = server_->Listen(1);
5690 CHECK(ok);
5691 listening_->Signal();
5692
5693 // Accept a connection.
5694 client_ = server_->Accept();
5695 CHECK(client_ != NULL);
5696
5697 // Receive a debugger agent protocol message.
5698 i::DebuggerAgentUtil::ReceiveMessage(client_);
5699}
5700
5701
5702TEST(DebuggerAgentProtocolOverflowHeader) {
5703 // Make sure this port is not used by other tests to allow tests to run in
5704 // parallel.
5705 const int kPort = 5860;
5706 static const char* kLocalhost = "localhost";
5707
5708 // Make a string with the port number.
5709 const int kPortBufferLen = 6;
5710 char port_str[kPortBufferLen];
5711 OS::SNPrintF(i::Vector<char>(port_str, kPortBufferLen), "%d", kPort);
5712
5713 // Initialize the socket library.
5714 i::Socket::Setup();
5715
5716 // Create a socket server to receive a debugger agent message.
5717 DebuggerAgentProtocolServerThread* server =
5718 new DebuggerAgentProtocolServerThread(kPort);
5719 server->Start();
5720 server->WaitForListening();
5721
5722 // Connect.
5723 i::Socket* client = i::OS::CreateSocket();
5724 CHECK(client != NULL);
5725 bool ok = client->Connect(kLocalhost, port_str);
5726 CHECK(ok);
5727
5728 // Send headers which overflow the receive buffer.
5729 static const int kBufferSize = 1000;
5730 char buffer[kBufferSize];
5731
5732 // Long key and short value: XXXX....XXXX:0\r\n.
5733 for (int i = 0; i < kBufferSize - 4; i++) {
5734 buffer[i] = 'X';
5735 }
5736 buffer[kBufferSize - 4] = ':';
5737 buffer[kBufferSize - 3] = '0';
5738 buffer[kBufferSize - 2] = '\r';
5739 buffer[kBufferSize - 1] = '\n';
5740 client->Send(buffer, kBufferSize);
5741
5742 // Short key and long value: X:XXXX....XXXX\r\n.
5743 buffer[0] = 'X';
5744 buffer[1] = ':';
5745 for (int i = 2; i < kBufferSize - 2; i++) {
5746 buffer[i] = 'X';
5747 }
5748 buffer[kBufferSize - 2] = '\r';
5749 buffer[kBufferSize - 1] = '\n';
5750 client->Send(buffer, kBufferSize);
5751
5752 // Add empty body to request.
5753 const char* content_length_zero_header = "Content-Length:0\r\n";
Steve Blockd0582a62009-12-15 09:54:21 +00005754 client->Send(content_length_zero_header,
5755 StrLength(content_length_zero_header));
Steve Blocka7e24c12009-10-30 11:49:00 +00005756 client->Send("\r\n", 2);
5757
5758 // Wait until data is received.
5759 server->Join();
5760
5761 // Check for empty body.
5762 CHECK(server->body() == NULL);
5763
5764 // Close the client before the server to avoid TIME_WAIT issues.
5765 client->Shutdown();
5766 delete client;
5767 delete server;
5768}
5769
5770
5771// Test for issue http://code.google.com/p/v8/issues/detail?id=289.
5772// Make sure that DebugGetLoadedScripts doesn't return scripts
5773// with disposed external source.
5774class EmptyExternalStringResource : public v8::String::ExternalStringResource {
5775 public:
5776 EmptyExternalStringResource() { empty_[0] = 0; }
5777 virtual ~EmptyExternalStringResource() {}
5778 virtual size_t length() const { return empty_.length(); }
5779 virtual const uint16_t* data() const { return empty_.start(); }
5780 private:
5781 ::v8::internal::EmbeddedVector<uint16_t, 1> empty_;
5782};
5783
5784
5785TEST(DebugGetLoadedScripts) {
5786 v8::HandleScope scope;
5787 DebugLocalContext env;
5788 env.ExposeDebug();
5789
5790 EmptyExternalStringResource source_ext_str;
5791 v8::Local<v8::String> source = v8::String::NewExternal(&source_ext_str);
5792 v8::Handle<v8::Script> evil_script = v8::Script::Compile(source);
5793 Handle<i::ExternalTwoByteString> i_source(
5794 i::ExternalTwoByteString::cast(*v8::Utils::OpenHandle(*source)));
5795 // This situation can happen if source was an external string disposed
5796 // by its owner.
5797 i_source->set_resource(0);
5798
5799 bool allow_natives_syntax = i::FLAG_allow_natives_syntax;
5800 i::FLAG_allow_natives_syntax = true;
5801 CompileRun(
5802 "var scripts = %DebugGetLoadedScripts();"
5803 "var count = scripts.length;"
5804 "for (var i = 0; i < count; ++i) {"
5805 " scripts[i].line_ends;"
5806 "}");
5807 // Must not crash while accessing line_ends.
5808 i::FLAG_allow_natives_syntax = allow_natives_syntax;
5809
5810 // Some scripts are retrieved - at least the number of native scripts.
5811 CHECK_GT((*env)->Global()->Get(v8::String::New("count"))->Int32Value(), 8);
5812}
5813
5814
5815// Test script break points set on lines.
5816TEST(ScriptNameAndData) {
5817 v8::HandleScope scope;
5818 DebugLocalContext env;
5819 env.ExposeDebug();
5820
5821 // Create functions for retrieving script name and data for the function on
5822 // the top frame when hitting a break point.
5823 frame_script_name = CompileFunction(&env,
5824 frame_script_name_source,
5825 "frame_script_name");
5826 frame_script_data = CompileFunction(&env,
5827 frame_script_data_source,
5828 "frame_script_data");
Andrei Popescu402d9372010-02-26 13:31:12 +00005829 compiled_script_data = CompileFunction(&env,
5830 compiled_script_data_source,
5831 "compiled_script_data");
Steve Blocka7e24c12009-10-30 11:49:00 +00005832
5833 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
5834 v8::Undefined());
5835
5836 // Test function source.
5837 v8::Local<v8::String> script = v8::String::New(
5838 "function f() {\n"
5839 " debugger;\n"
5840 "}\n");
5841
5842 v8::ScriptOrigin origin1 = v8::ScriptOrigin(v8::String::New("name"));
5843 v8::Handle<v8::Script> script1 = v8::Script::Compile(script, &origin1);
5844 script1->SetData(v8::String::New("data"));
5845 script1->Run();
5846 v8::Local<v8::Function> f;
5847 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
5848
5849 f->Call(env->Global(), 0, NULL);
5850 CHECK_EQ(1, break_point_hit_count);
5851 CHECK_EQ("name", last_script_name_hit);
5852 CHECK_EQ("data", last_script_data_hit);
5853
5854 // Compile the same script again without setting data. As the compilation
5855 // cache is disabled when debugging expect the data to be missing.
5856 v8::Script::Compile(script, &origin1)->Run();
5857 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
5858 f->Call(env->Global(), 0, NULL);
5859 CHECK_EQ(2, break_point_hit_count);
5860 CHECK_EQ("name", last_script_name_hit);
5861 CHECK_EQ("", last_script_data_hit); // Undefined results in empty string.
5862
5863 v8::Local<v8::String> data_obj_source = v8::String::New(
5864 "({ a: 'abc',\n"
5865 " b: 123,\n"
5866 " toString: function() { return this.a + ' ' + this.b; }\n"
5867 "})\n");
5868 v8::Local<v8::Value> data_obj = v8::Script::Compile(data_obj_source)->Run();
5869 v8::ScriptOrigin origin2 = v8::ScriptOrigin(v8::String::New("new name"));
5870 v8::Handle<v8::Script> script2 = v8::Script::Compile(script, &origin2);
5871 script2->Run();
Steve Blockd0582a62009-12-15 09:54:21 +00005872 script2->SetData(data_obj->ToString());
Steve Blocka7e24c12009-10-30 11:49:00 +00005873 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
5874 f->Call(env->Global(), 0, NULL);
5875 CHECK_EQ(3, break_point_hit_count);
5876 CHECK_EQ("new name", last_script_name_hit);
5877 CHECK_EQ("abc 123", last_script_data_hit);
Andrei Popescu402d9372010-02-26 13:31:12 +00005878
5879 v8::Handle<v8::Script> script3 =
5880 v8::Script::Compile(script, &origin2, NULL,
5881 v8::String::New("in compile"));
5882 CHECK_EQ("in compile", last_script_data_hit);
5883 script3->Run();
5884 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
5885 f->Call(env->Global(), 0, NULL);
5886 CHECK_EQ(4, break_point_hit_count);
5887 CHECK_EQ("in compile", last_script_data_hit);
Steve Blocka7e24c12009-10-30 11:49:00 +00005888}
5889
5890
5891static v8::Persistent<v8::Context> expected_context;
5892static v8::Handle<v8::Value> expected_context_data;
5893
5894
5895// Check that the expected context is the one generating the debug event.
5896static void ContextCheckMessageHandler(const v8::Debug::Message& message) {
5897 CHECK(message.GetEventContext() == expected_context);
5898 CHECK(message.GetEventContext()->GetData()->StrictEquals(
5899 expected_context_data));
5900 message_handler_hit_count++;
5901
Steve Block3ce2e202009-11-05 08:53:23 +00005902 static char print_buffer[1000];
5903 v8::String::Value json(message.GetJSON());
5904 Utf16ToAscii(*json, json.length(), print_buffer);
5905
Steve Blocka7e24c12009-10-30 11:49:00 +00005906 // Send a continue command for break events.
Steve Block3ce2e202009-11-05 08:53:23 +00005907 if (IsBreakEventMessage(print_buffer)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005908 SendContinueCommand();
5909 }
5910}
5911
5912
5913// Test which creates two contexts and sets different embedder data on each.
5914// Checks that this data is set correctly and that when the debug message
5915// handler is called the expected context is the one active.
5916TEST(ContextData) {
5917 v8::HandleScope scope;
5918
5919 v8::Debug::SetMessageHandler2(ContextCheckMessageHandler);
5920
5921 // Create two contexts.
5922 v8::Persistent<v8::Context> context_1;
5923 v8::Persistent<v8::Context> context_2;
5924 v8::Handle<v8::ObjectTemplate> global_template =
5925 v8::Handle<v8::ObjectTemplate>();
5926 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>();
5927 context_1 = v8::Context::New(NULL, global_template, global_object);
5928 context_2 = v8::Context::New(NULL, global_template, global_object);
5929
5930 // Default data value is undefined.
5931 CHECK(context_1->GetData()->IsUndefined());
5932 CHECK(context_2->GetData()->IsUndefined());
5933
5934 // Set and check different data values.
Steve Blockd0582a62009-12-15 09:54:21 +00005935 v8::Handle<v8::String> data_1 = v8::String::New("1");
5936 v8::Handle<v8::String> data_2 = v8::String::New("2");
Steve Blocka7e24c12009-10-30 11:49:00 +00005937 context_1->SetData(data_1);
5938 context_2->SetData(data_2);
5939 CHECK(context_1->GetData()->StrictEquals(data_1));
5940 CHECK(context_2->GetData()->StrictEquals(data_2));
5941
5942 // Simple test function which causes a break.
5943 const char* source = "function f() { debugger; }";
5944
5945 // Enter and run function in the first context.
5946 {
5947 v8::Context::Scope context_scope(context_1);
5948 expected_context = context_1;
5949 expected_context_data = data_1;
5950 v8::Local<v8::Function> f = CompileFunction(source, "f");
5951 f->Call(context_1->Global(), 0, NULL);
5952 }
5953
5954
5955 // Enter and run function in the second context.
5956 {
5957 v8::Context::Scope context_scope(context_2);
5958 expected_context = context_2;
5959 expected_context_data = data_2;
5960 v8::Local<v8::Function> f = CompileFunction(source, "f");
5961 f->Call(context_2->Global(), 0, NULL);
5962 }
5963
5964 // Two times compile event and two times break event.
5965 CHECK_GT(message_handler_hit_count, 4);
5966
5967 v8::Debug::SetMessageHandler2(NULL);
5968 CheckDebuggerUnloaded();
5969}
5970
5971
5972// Debug message handler which issues a debug break when it hits a break event.
5973static int message_handler_break_hit_count = 0;
5974static void DebugBreakMessageHandler(const v8::Debug::Message& message) {
5975 // Schedule a debug break for break events.
5976 if (message.IsEvent() && message.GetEvent() == v8::Break) {
5977 message_handler_break_hit_count++;
5978 if (message_handler_break_hit_count == 1) {
5979 v8::Debug::DebugBreak();
5980 }
5981 }
5982
5983 // Issue a continue command if this event will not cause the VM to start
5984 // running.
5985 if (!message.WillStartRunning()) {
5986 SendContinueCommand();
5987 }
5988}
5989
5990
5991// Test that a debug break can be scheduled while in a message handler.
5992TEST(DebugBreakInMessageHandler) {
5993 v8::HandleScope scope;
5994 DebugLocalContext env;
5995
5996 v8::Debug::SetMessageHandler2(DebugBreakMessageHandler);
5997
5998 // Test functions.
5999 const char* script = "function f() { debugger; g(); } function g() { }";
6000 CompileRun(script);
6001 v8::Local<v8::Function> f =
6002 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6003 v8::Local<v8::Function> g =
6004 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
6005
6006 // Call f then g. The debugger statement in f will casue a break which will
6007 // cause another break.
6008 f->Call(env->Global(), 0, NULL);
6009 CHECK_EQ(2, message_handler_break_hit_count);
6010 // Calling g will not cause any additional breaks.
6011 g->Call(env->Global(), 0, NULL);
6012 CHECK_EQ(2, message_handler_break_hit_count);
6013}
6014
6015
Steve Block6ded16b2010-05-10 14:33:55 +01006016#ifndef V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +00006017// Debug event handler which gets the function on the top frame and schedules a
6018// break a number of times.
6019static void DebugEventDebugBreak(
6020 v8::DebugEvent event,
6021 v8::Handle<v8::Object> exec_state,
6022 v8::Handle<v8::Object> event_data,
6023 v8::Handle<v8::Value> data) {
6024
6025 if (event == v8::Break) {
6026 break_point_hit_count++;
6027
6028 // Get the name of the top frame function.
6029 if (!frame_function_name.IsEmpty()) {
6030 // Get the name of the function.
6031 const int argc = 1;
6032 v8::Handle<v8::Value> argv[argc] = { exec_state };
6033 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
6034 argc, argv);
6035 if (result->IsUndefined()) {
6036 last_function_hit[0] = '\0';
6037 } else {
6038 CHECK(result->IsString());
6039 v8::Handle<v8::String> function_name(result->ToString());
6040 function_name->WriteAscii(last_function_hit);
6041 }
6042 }
6043
6044 // Keep forcing breaks.
6045 if (break_point_hit_count < 20) {
6046 v8::Debug::DebugBreak();
6047 }
6048 }
6049}
6050
6051
6052TEST(RegExpDebugBreak) {
6053 // This test only applies to native regexps.
6054 v8::HandleScope scope;
6055 DebugLocalContext env;
6056
6057 // Create a function for checking the function when hitting a break point.
6058 frame_function_name = CompileFunction(&env,
6059 frame_function_name_source,
6060 "frame_function_name");
6061
6062 // Test RegExp which matches white spaces and comments at the begining of a
6063 // source line.
6064 const char* script =
6065 "var sourceLineBeginningSkip = /^(?:[ \\v\\h]*(?:\\/\\*.*?\\*\\/)*)*/;\n"
6066 "function f(s) { return s.match(sourceLineBeginningSkip)[0].length; }";
6067
6068 v8::Local<v8::Function> f = CompileFunction(script, "f");
6069 const int argc = 1;
6070 v8::Handle<v8::Value> argv[argc] = { v8::String::New(" /* xxx */ a=0;") };
6071 v8::Local<v8::Value> result = f->Call(env->Global(), argc, argv);
6072 CHECK_EQ(12, result->Int32Value());
6073
6074 v8::Debug::SetDebugEventListener(DebugEventDebugBreak);
6075 v8::Debug::DebugBreak();
6076 result = f->Call(env->Global(), argc, argv);
6077
6078 // Check that there was only one break event. Matching RegExp should not
6079 // cause Break events.
6080 CHECK_EQ(1, break_point_hit_count);
6081 CHECK_EQ("f", last_function_hit);
6082}
Steve Block6ded16b2010-05-10 14:33:55 +01006083#endif // V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +00006084
6085
6086// Common part of EvalContextData and NestedBreakEventContextData tests.
6087static void ExecuteScriptForContextCheck() {
6088 // Create a context.
6089 v8::Persistent<v8::Context> context_1;
6090 v8::Handle<v8::ObjectTemplate> global_template =
6091 v8::Handle<v8::ObjectTemplate>();
6092 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>();
6093 context_1 = v8::Context::New(NULL, global_template, global_object);
6094
6095 // Default data value is undefined.
6096 CHECK(context_1->GetData()->IsUndefined());
6097
6098 // Set and check a data value.
Steve Blockd0582a62009-12-15 09:54:21 +00006099 v8::Handle<v8::String> data_1 = v8::String::New("1");
Steve Blocka7e24c12009-10-30 11:49:00 +00006100 context_1->SetData(data_1);
6101 CHECK(context_1->GetData()->StrictEquals(data_1));
6102
6103 // Simple test function with eval that causes a break.
6104 const char* source = "function f() { eval('debugger;'); }";
6105
6106 // Enter and run function in the context.
6107 {
6108 v8::Context::Scope context_scope(context_1);
6109 expected_context = context_1;
6110 expected_context_data = data_1;
6111 v8::Local<v8::Function> f = CompileFunction(source, "f");
6112 f->Call(context_1->Global(), 0, NULL);
6113 }
6114}
6115
6116
6117// Test which creates a context and sets embedder data on it. Checks that this
6118// data is set correctly and that when the debug message handler is called for
6119// break event in an eval statement the expected context is the one returned by
6120// Message.GetEventContext.
6121TEST(EvalContextData) {
6122 v8::HandleScope scope;
6123 v8::Debug::SetMessageHandler2(ContextCheckMessageHandler);
6124
6125 ExecuteScriptForContextCheck();
6126
6127 // One time compile event and one time break event.
6128 CHECK_GT(message_handler_hit_count, 2);
6129 v8::Debug::SetMessageHandler2(NULL);
6130 CheckDebuggerUnloaded();
6131}
6132
6133
6134static bool sent_eval = false;
6135static int break_count = 0;
6136static int continue_command_send_count = 0;
6137// Check that the expected context is the one generating the debug event
6138// including the case of nested break event.
6139static void DebugEvalContextCheckMessageHandler(
6140 const v8::Debug::Message& message) {
6141 CHECK(message.GetEventContext() == expected_context);
6142 CHECK(message.GetEventContext()->GetData()->StrictEquals(
6143 expected_context_data));
6144 message_handler_hit_count++;
6145
Steve Block3ce2e202009-11-05 08:53:23 +00006146 static char print_buffer[1000];
6147 v8::String::Value json(message.GetJSON());
6148 Utf16ToAscii(*json, json.length(), print_buffer);
6149
6150 if (IsBreakEventMessage(print_buffer)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006151 break_count++;
6152 if (!sent_eval) {
6153 sent_eval = true;
6154
6155 const int kBufferSize = 1000;
6156 uint16_t buffer[kBufferSize];
6157 const char* eval_command =
6158 "{\"seq\":0,"
6159 "\"type\":\"request\","
6160 "\"command\":\"evaluate\","
6161 "arguments:{\"expression\":\"debugger;\","
6162 "\"global\":true,\"disable_break\":false}}";
6163
6164 // Send evaluate command.
6165 v8::Debug::SendCommand(buffer, AsciiToUtf16(eval_command, buffer));
6166 return;
6167 } else {
6168 // It's a break event caused by the evaluation request above.
6169 SendContinueCommand();
6170 continue_command_send_count++;
6171 }
Steve Block3ce2e202009-11-05 08:53:23 +00006172 } else if (IsEvaluateResponseMessage(print_buffer) &&
6173 continue_command_send_count < 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006174 // Response to the evaluation request. We're still on the breakpoint so
6175 // send continue.
6176 SendContinueCommand();
6177 continue_command_send_count++;
6178 }
6179}
6180
6181
6182// Tests that context returned for break event is correct when the event occurs
6183// in 'evaluate' debugger request.
6184TEST(NestedBreakEventContextData) {
6185 v8::HandleScope scope;
6186 break_count = 0;
6187 message_handler_hit_count = 0;
6188 v8::Debug::SetMessageHandler2(DebugEvalContextCheckMessageHandler);
6189
6190 ExecuteScriptForContextCheck();
6191
6192 // One time compile event and two times break event.
6193 CHECK_GT(message_handler_hit_count, 3);
6194
6195 // One break from the source and another from the evaluate request.
6196 CHECK_EQ(break_count, 2);
6197 v8::Debug::SetMessageHandler2(NULL);
6198 CheckDebuggerUnloaded();
6199}
6200
6201
6202// Debug event listener which counts the script collected events.
6203int script_collected_count = 0;
6204static void DebugEventScriptCollectedEvent(v8::DebugEvent event,
6205 v8::Handle<v8::Object> exec_state,
6206 v8::Handle<v8::Object> event_data,
6207 v8::Handle<v8::Value> data) {
6208 // Count the number of breaks.
6209 if (event == v8::ScriptCollected) {
6210 script_collected_count++;
6211 }
6212}
6213
6214
6215// Test that scripts collected are reported through the debug event listener.
6216TEST(ScriptCollectedEvent) {
6217 break_point_hit_count = 0;
6218 script_collected_count = 0;
6219 v8::HandleScope scope;
6220 DebugLocalContext env;
6221
6222 // Request the loaded scripts to initialize the debugger script cache.
6223 Debug::GetLoadedScripts();
6224
6225 // Do garbage collection to ensure that only the script in this test will be
6226 // collected afterwards.
6227 Heap::CollectAllGarbage(false);
6228
6229 script_collected_count = 0;
6230 v8::Debug::SetDebugEventListener(DebugEventScriptCollectedEvent,
6231 v8::Undefined());
6232 {
6233 v8::Script::Compile(v8::String::New("eval('a=1')"))->Run();
6234 v8::Script::Compile(v8::String::New("eval('a=2')"))->Run();
6235 }
6236
6237 // Do garbage collection to collect the script above which is no longer
6238 // referenced.
6239 Heap::CollectAllGarbage(false);
6240
6241 CHECK_EQ(2, script_collected_count);
6242
6243 v8::Debug::SetDebugEventListener(NULL);
6244 CheckDebuggerUnloaded();
6245}
6246
6247
6248// Debug event listener which counts the script collected events.
6249int script_collected_message_count = 0;
6250static void ScriptCollectedMessageHandler(const v8::Debug::Message& message) {
6251 // Count the number of scripts collected.
6252 if (message.IsEvent() && message.GetEvent() == v8::ScriptCollected) {
6253 script_collected_message_count++;
6254 v8::Handle<v8::Context> context = message.GetEventContext();
6255 CHECK(context.IsEmpty());
6256 }
6257}
6258
6259
6260// Test that GetEventContext doesn't fail and return empty handle for
6261// ScriptCollected events.
6262TEST(ScriptCollectedEventContext) {
6263 script_collected_message_count = 0;
6264 v8::HandleScope scope;
6265
6266 { // Scope for the DebugLocalContext.
6267 DebugLocalContext env;
6268
6269 // Request the loaded scripts to initialize the debugger script cache.
6270 Debug::GetLoadedScripts();
6271
6272 // Do garbage collection to ensure that only the script in this test will be
6273 // collected afterwards.
6274 Heap::CollectAllGarbage(false);
6275
6276 v8::Debug::SetMessageHandler2(ScriptCollectedMessageHandler);
6277 {
6278 v8::Script::Compile(v8::String::New("eval('a=1')"))->Run();
6279 v8::Script::Compile(v8::String::New("eval('a=2')"))->Run();
6280 }
6281 }
6282
6283 // Do garbage collection to collect the script above which is no longer
6284 // referenced.
6285 Heap::CollectAllGarbage(false);
6286
6287 CHECK_EQ(2, script_collected_message_count);
6288
6289 v8::Debug::SetMessageHandler2(NULL);
6290}
6291
6292
6293// Debug event listener which counts the after compile events.
6294int after_compile_message_count = 0;
6295static void AfterCompileMessageHandler(const v8::Debug::Message& message) {
6296 // Count the number of scripts collected.
6297 if (message.IsEvent()) {
6298 if (message.GetEvent() == v8::AfterCompile) {
6299 after_compile_message_count++;
6300 } else if (message.GetEvent() == v8::Break) {
6301 SendContinueCommand();
6302 }
6303 }
6304}
6305
6306
6307// Tests that after compile event is sent as many times as there are scripts
6308// compiled.
6309TEST(AfterCompileMessageWhenMessageHandlerIsReset) {
6310 v8::HandleScope scope;
6311 DebugLocalContext env;
6312 after_compile_message_count = 0;
6313 const char* script = "var a=1";
6314
6315 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6316 v8::Script::Compile(v8::String::New(script))->Run();
6317 v8::Debug::SetMessageHandler2(NULL);
6318
6319 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6320 v8::Debug::DebugBreak();
6321 v8::Script::Compile(v8::String::New(script))->Run();
6322
6323 // Setting listener to NULL should cause debugger unload.
6324 v8::Debug::SetMessageHandler2(NULL);
6325 CheckDebuggerUnloaded();
6326
6327 // Compilation cache should be disabled when debugger is active.
6328 CHECK_EQ(2, after_compile_message_count);
6329}
6330
6331
6332// Tests that break event is sent when message handler is reset.
6333TEST(BreakMessageWhenMessageHandlerIsReset) {
6334 v8::HandleScope scope;
6335 DebugLocalContext env;
6336 after_compile_message_count = 0;
6337 const char* script = "function f() {};";
6338
6339 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6340 v8::Script::Compile(v8::String::New(script))->Run();
6341 v8::Debug::SetMessageHandler2(NULL);
6342
6343 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6344 v8::Debug::DebugBreak();
6345 v8::Local<v8::Function> f =
6346 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6347 f->Call(env->Global(), 0, NULL);
6348
6349 // Setting message handler to NULL should cause debugger unload.
6350 v8::Debug::SetMessageHandler2(NULL);
6351 CheckDebuggerUnloaded();
6352
6353 // Compilation cache should be disabled when debugger is active.
6354 CHECK_EQ(1, after_compile_message_count);
6355}
6356
6357
6358static int exception_event_count = 0;
6359static void ExceptionMessageHandler(const v8::Debug::Message& message) {
6360 if (message.IsEvent() && message.GetEvent() == v8::Exception) {
6361 exception_event_count++;
6362 SendContinueCommand();
6363 }
6364}
6365
6366
6367// Tests that exception event is sent when message handler is reset.
6368TEST(ExceptionMessageWhenMessageHandlerIsReset) {
6369 v8::HandleScope scope;
6370 DebugLocalContext env;
6371 exception_event_count = 0;
6372 const char* script = "function f() {throw new Error()};";
6373
6374 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6375 v8::Script::Compile(v8::String::New(script))->Run();
6376 v8::Debug::SetMessageHandler2(NULL);
6377
6378 v8::Debug::SetMessageHandler2(ExceptionMessageHandler);
6379 v8::Local<v8::Function> f =
6380 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6381 f->Call(env->Global(), 0, NULL);
6382
6383 // Setting message handler to NULL should cause debugger unload.
6384 v8::Debug::SetMessageHandler2(NULL);
6385 CheckDebuggerUnloaded();
6386
6387 CHECK_EQ(1, exception_event_count);
6388}
6389
6390
6391// Tests after compile event is sent when there are some provisional
6392// breakpoints out of the scripts lines range.
6393TEST(ProvisionalBreakpointOnLineOutOfRange) {
6394 v8::HandleScope scope;
6395 DebugLocalContext env;
6396 env.ExposeDebug();
6397 const char* script = "function f() {};";
6398 const char* resource_name = "test_resource";
6399
6400 // Set a couple of provisional breakpoint on lines out of the script lines
6401 // range.
6402 int sbp1 = SetScriptBreakPointByNameFromJS(resource_name, 3,
6403 -1 /* no column */);
6404 int sbp2 = SetScriptBreakPointByNameFromJS(resource_name, 5, 5);
6405
6406 after_compile_message_count = 0;
6407 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6408
6409 v8::ScriptOrigin origin(
6410 v8::String::New(resource_name),
6411 v8::Integer::New(10),
6412 v8::Integer::New(1));
6413 // Compile a script whose first line number is greater than the breakpoints'
6414 // lines.
6415 v8::Script::Compile(v8::String::New(script), &origin)->Run();
6416
6417 // If the script is compiled successfully there is exactly one after compile
6418 // event. In case of an exception in debugger code after compile event is not
6419 // sent.
6420 CHECK_EQ(1, after_compile_message_count);
6421
6422 ClearBreakPointFromJS(sbp1);
6423 ClearBreakPointFromJS(sbp2);
6424 v8::Debug::SetMessageHandler2(NULL);
6425}
6426
6427
6428static void BreakMessageHandler(const v8::Debug::Message& message) {
6429 if (message.IsEvent() && message.GetEvent() == v8::Break) {
6430 // Count the number of breaks.
6431 break_point_hit_count++;
6432
6433 v8::HandleScope scope;
6434 v8::Handle<v8::String> json = message.GetJSON();
6435
6436 SendContinueCommand();
6437 } else if (message.IsEvent() && message.GetEvent() == v8::AfterCompile) {
6438 v8::HandleScope scope;
6439
6440 bool is_debug_break = i::StackGuard::IsDebugBreak();
6441 // Force DebugBreak flag while serializer is working.
6442 i::StackGuard::DebugBreak();
6443
6444 // Force serialization to trigger some internal JS execution.
6445 v8::Handle<v8::String> json = message.GetJSON();
6446
6447 // Restore previous state.
6448 if (is_debug_break) {
6449 i::StackGuard::DebugBreak();
6450 } else {
6451 i::StackGuard::Continue(i::DEBUGBREAK);
6452 }
6453 }
6454}
6455
6456
6457// Test that if DebugBreak is forced it is ignored when code from
6458// debug-delay.js is executed.
6459TEST(NoDebugBreakInAfterCompileMessageHandler) {
6460 v8::HandleScope scope;
6461 DebugLocalContext env;
6462
6463 // Register a debug event listener which sets the break flag and counts.
6464 v8::Debug::SetMessageHandler2(BreakMessageHandler);
6465
6466 // Set the debug break flag.
6467 v8::Debug::DebugBreak();
6468
6469 // Create a function for testing stepping.
6470 const char* src = "function f() { eval('var x = 10;'); } ";
6471 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
6472
6473 // There should be only one break event.
6474 CHECK_EQ(1, break_point_hit_count);
6475
6476 // Set the debug break flag again.
6477 v8::Debug::DebugBreak();
6478 f->Call(env->Global(), 0, NULL);
6479 // There should be one more break event when the script is evaluated in 'f'.
6480 CHECK_EQ(2, break_point_hit_count);
6481
6482 // Get rid of the debug message handler.
6483 v8::Debug::SetMessageHandler2(NULL);
6484 CheckDebuggerUnloaded();
6485}
6486
6487
Leon Clarkee46be812010-01-19 14:06:41 +00006488static int counting_message_handler_counter;
6489
6490static void CountingMessageHandler(const v8::Debug::Message& message) {
6491 counting_message_handler_counter++;
6492}
6493
6494// Test that debug messages get processed when ProcessDebugMessages is called.
6495TEST(ProcessDebugMessages) {
6496 v8::HandleScope scope;
6497 DebugLocalContext env;
6498
6499 counting_message_handler_counter = 0;
6500
6501 v8::Debug::SetMessageHandler2(CountingMessageHandler);
6502
6503 const int kBufferSize = 1000;
6504 uint16_t buffer[kBufferSize];
6505 const char* scripts_command =
6506 "{\"seq\":0,"
6507 "\"type\":\"request\","
6508 "\"command\":\"scripts\"}";
6509
6510 // Send scripts command.
6511 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6512
6513 CHECK_EQ(0, counting_message_handler_counter);
6514 v8::Debug::ProcessDebugMessages();
6515 // At least one message should come
6516 CHECK_GE(counting_message_handler_counter, 1);
6517
6518 counting_message_handler_counter = 0;
6519
6520 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6521 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6522 CHECK_EQ(0, counting_message_handler_counter);
6523 v8::Debug::ProcessDebugMessages();
6524 // At least two messages should come
6525 CHECK_GE(counting_message_handler_counter, 2);
6526
6527 // Get rid of the debug message handler.
6528 v8::Debug::SetMessageHandler2(NULL);
6529 CheckDebuggerUnloaded();
6530}
6531
6532
Steve Block6ded16b2010-05-10 14:33:55 +01006533struct BacktraceData {
Leon Clarked91b9f72010-01-27 17:25:45 +00006534 static int frame_counter;
6535 static void MessageHandler(const v8::Debug::Message& message) {
6536 char print_buffer[1000];
6537 v8::String::Value json(message.GetJSON());
6538 Utf16ToAscii(*json, json.length(), print_buffer, 1000);
6539
6540 if (strstr(print_buffer, "backtrace") == NULL) {
6541 return;
6542 }
6543 frame_counter = GetTotalFramesInt(print_buffer);
6544 }
6545};
6546
Steve Block6ded16b2010-05-10 14:33:55 +01006547int BacktraceData::frame_counter;
Leon Clarked91b9f72010-01-27 17:25:45 +00006548
6549
6550// Test that debug messages get processed when ProcessDebugMessages is called.
6551TEST(Backtrace) {
6552 v8::HandleScope scope;
6553 DebugLocalContext env;
6554
Steve Block6ded16b2010-05-10 14:33:55 +01006555 v8::Debug::SetMessageHandler2(BacktraceData::MessageHandler);
Leon Clarked91b9f72010-01-27 17:25:45 +00006556
6557 const int kBufferSize = 1000;
6558 uint16_t buffer[kBufferSize];
6559 const char* scripts_command =
6560 "{\"seq\":0,"
6561 "\"type\":\"request\","
6562 "\"command\":\"backtrace\"}";
6563
6564 // Check backtrace from ProcessDebugMessages.
Steve Block6ded16b2010-05-10 14:33:55 +01006565 BacktraceData::frame_counter = -10;
Leon Clarked91b9f72010-01-27 17:25:45 +00006566 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6567 v8::Debug::ProcessDebugMessages();
Steve Block6ded16b2010-05-10 14:33:55 +01006568 CHECK_EQ(BacktraceData::frame_counter, 0);
Leon Clarked91b9f72010-01-27 17:25:45 +00006569
6570 v8::Handle<v8::String> void0 = v8::String::New("void(0)");
6571 v8::Handle<v8::Script> script = v8::Script::Compile(void0, void0);
6572
6573 // Check backtrace from "void(0)" script.
Steve Block6ded16b2010-05-10 14:33:55 +01006574 BacktraceData::frame_counter = -10;
Leon Clarked91b9f72010-01-27 17:25:45 +00006575 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6576 script->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01006577 CHECK_EQ(BacktraceData::frame_counter, 1);
Leon Clarked91b9f72010-01-27 17:25:45 +00006578
6579 // Get rid of the debug message handler.
6580 v8::Debug::SetMessageHandler2(NULL);
6581 CheckDebuggerUnloaded();
6582}
6583
6584
Steve Blocka7e24c12009-10-30 11:49:00 +00006585TEST(GetMirror) {
6586 v8::HandleScope scope;
6587 DebugLocalContext env;
6588 v8::Handle<v8::Value> obj = v8::Debug::GetMirror(v8::String::New("hodja"));
6589 v8::Handle<v8::Function> run_test = v8::Handle<v8::Function>::Cast(
6590 v8::Script::New(
6591 v8::String::New(
6592 "function runTest(mirror) {"
6593 " return mirror.isString() && (mirror.length() == 5);"
6594 "}"
6595 ""
6596 "runTest;"))->Run());
6597 v8::Handle<v8::Value> result = run_test->Call(env->Global(), 1, &obj);
6598 CHECK(result->IsTrue());
6599}
Steve Blockd0582a62009-12-15 09:54:21 +00006600
6601
6602// Test that the debug break flag works with function.apply.
6603TEST(DebugBreakFunctionApply) {
6604 v8::HandleScope scope;
6605 DebugLocalContext env;
6606
6607 // Create a function for testing breaking in apply.
6608 v8::Local<v8::Function> foo = CompileFunction(
6609 &env,
6610 "function baz(x) { }"
6611 "function bar(x) { baz(); }"
6612 "function foo(){ bar.apply(this, [1]); }",
6613 "foo");
6614
6615 // Register a debug event listener which steps and counts.
6616 v8::Debug::SetDebugEventListener(DebugEventBreakMax);
6617
6618 // Set the debug break flag before calling the code using function.apply.
6619 v8::Debug::DebugBreak();
6620
6621 // Limit the number of debug breaks. This is a regression test for issue 493
6622 // where this test would enter an infinite loop.
6623 break_point_hit_count = 0;
6624 max_break_point_hit_count = 10000; // 10000 => infinite loop.
6625 foo->Call(env->Global(), 0, NULL);
6626
6627 // When keeping the debug break several break will happen.
6628 CHECK_EQ(3, break_point_hit_count);
6629
6630 v8::Debug::SetDebugEventListener(NULL);
6631 CheckDebuggerUnloaded();
6632}
6633
6634
6635v8::Handle<v8::Context> debugee_context;
6636v8::Handle<v8::Context> debugger_context;
6637
6638
6639// Property getter that checks that current and calling contexts
6640// are both the debugee contexts.
6641static v8::Handle<v8::Value> NamedGetterWithCallingContextCheck(
6642 v8::Local<v8::String> name,
6643 const v8::AccessorInfo& info) {
6644 CHECK_EQ(0, strcmp(*v8::String::AsciiValue(name), "a"));
6645 v8::Handle<v8::Context> current = v8::Context::GetCurrent();
6646 CHECK(current == debugee_context);
6647 CHECK(current != debugger_context);
6648 v8::Handle<v8::Context> calling = v8::Context::GetCalling();
6649 CHECK(calling == debugee_context);
6650 CHECK(calling != debugger_context);
6651 return v8::Int32::New(1);
6652}
6653
6654
6655// Debug event listener that checks if the first argument of a function is
6656// an object with property 'a' == 1. If the property has custom accessor
6657// this handler will eventually invoke it.
6658static void DebugEventGetAtgumentPropertyValue(
6659 v8::DebugEvent event,
6660 v8::Handle<v8::Object> exec_state,
6661 v8::Handle<v8::Object> event_data,
6662 v8::Handle<v8::Value> data) {
6663 if (event == v8::Break) {
6664 break_point_hit_count++;
6665 CHECK(debugger_context == v8::Context::GetCurrent());
6666 v8::Handle<v8::Function> func(v8::Function::Cast(*CompileRun(
6667 "(function(exec_state) {\n"
6668 " return (exec_state.frame(0).argumentValue(0).property('a').\n"
6669 " value().value() == 1);\n"
6670 "})")));
6671 const int argc = 1;
6672 v8::Handle<v8::Value> argv[argc] = { exec_state };
6673 v8::Handle<v8::Value> result = func->Call(exec_state, argc, argv);
6674 CHECK(result->IsTrue());
6675 }
6676}
6677
6678
6679TEST(CallingContextIsNotDebugContext) {
6680 // Create and enter a debugee context.
6681 v8::HandleScope scope;
6682 DebugLocalContext env;
6683 env.ExposeDebug();
6684
6685 // Save handles to the debugger and debugee contexts to be used in
6686 // NamedGetterWithCallingContextCheck.
6687 debugee_context = v8::Local<v8::Context>(*env);
6688 debugger_context = v8::Utils::ToLocal(Debug::debug_context());
6689
6690 // Create object with 'a' property accessor.
6691 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
6692 named->SetAccessor(v8::String::New("a"),
6693 NamedGetterWithCallingContextCheck);
6694 env->Global()->Set(v8::String::New("obj"),
6695 named->NewInstance());
6696
6697 // Register the debug event listener
6698 v8::Debug::SetDebugEventListener(DebugEventGetAtgumentPropertyValue);
6699
6700 // Create a function that invokes debugger.
6701 v8::Local<v8::Function> foo = CompileFunction(
6702 &env,
6703 "function bar(x) { debugger; }"
6704 "function foo(){ bar(obj); }",
6705 "foo");
6706
6707 break_point_hit_count = 0;
6708 foo->Call(env->Global(), 0, NULL);
6709 CHECK_EQ(1, break_point_hit_count);
6710
6711 v8::Debug::SetDebugEventListener(NULL);
6712 debugee_context = v8::Handle<v8::Context>();
6713 debugger_context = v8::Handle<v8::Context>();
6714 CheckDebuggerUnloaded();
6715}
Steve Block6ded16b2010-05-10 14:33:55 +01006716
6717
6718TEST(DebugContextIsPreservedBetweenAccesses) {
6719 v8::HandleScope scope;
6720 v8::Local<v8::Context> context1 = v8::Debug::GetDebugContext();
6721 v8::Local<v8::Context> context2 = v8::Debug::GetDebugContext();
6722 CHECK_EQ(*context1, *context2);
Leon Clarkef7060e22010-06-03 12:02:55 +01006723}
6724
6725
6726static v8::Handle<v8::Value> expected_callback_data;
6727static void DebugEventContextChecker(const v8::Debug::EventDetails& details) {
6728 CHECK(details.GetEventContext() == expected_context);
6729 CHECK_EQ(expected_callback_data, details.GetCallbackData());
6730}
6731
6732// Check that event details contain context where debug event occured.
6733TEST(DebugEventContext) {
6734 v8::HandleScope scope;
6735 expected_callback_data = v8::Int32::New(2010);
6736 v8::Debug::SetDebugEventListener2(DebugEventContextChecker,
6737 expected_callback_data);
6738 expected_context = v8::Context::New();
6739 v8::Context::Scope context_scope(expected_context);
6740 v8::Script::Compile(v8::String::New("(function(){debugger;})();"))->Run();
6741 expected_context.Dispose();
6742 expected_context.Clear();
6743 v8::Debug::SetDebugEventListener(NULL);
6744 expected_context_data = v8::Handle<v8::Value>();
Steve Block6ded16b2010-05-10 14:33:55 +01006745 CheckDebuggerUnloaded();
6746}
Leon Clarkef7060e22010-06-03 12:02:55 +01006747
Ben Murdoch3bec4d22010-07-22 14:51:16 +01006748
6749static void* expected_break_data;
6750static bool was_debug_break_called;
6751static bool was_debug_event_called;
6752static void DebugEventBreakDataChecker(const v8::Debug::EventDetails& details) {
6753 if (details.GetEvent() == v8::BreakForCommand) {
6754 CHECK_EQ(expected_break_data, details.GetClientData());
6755 was_debug_event_called = true;
6756 } else if (details.GetEvent() == v8::Break) {
6757 was_debug_break_called = true;
6758 }
6759}
6760
6761// Check that event details contain context where debug event occured.
6762TEST(DebugEventBreakData) {
6763 v8::HandleScope scope;
6764 DebugLocalContext env;
6765 v8::Debug::SetDebugEventListener2(DebugEventBreakDataChecker);
6766
6767 TestClientData::constructor_call_counter = 0;
6768 TestClientData::destructor_call_counter = 0;
6769
6770 expected_break_data = NULL;
6771 was_debug_event_called = false;
6772 was_debug_break_called = false;
6773 v8::Debug::DebugBreakForCommand();
6774 v8::Script::Compile(v8::String::New("(function(x){return x;})(1);"))->Run();
6775 CHECK(was_debug_event_called);
6776 CHECK(!was_debug_break_called);
6777
6778 TestClientData* data1 = new TestClientData();
6779 expected_break_data = data1;
6780 was_debug_event_called = false;
6781 was_debug_break_called = false;
6782 v8::Debug::DebugBreakForCommand(data1);
6783 v8::Script::Compile(v8::String::New("(function(x){return x+1;})(1);"))->Run();
6784 CHECK(was_debug_event_called);
6785 CHECK(!was_debug_break_called);
6786
6787 expected_break_data = NULL;
6788 was_debug_event_called = false;
6789 was_debug_break_called = false;
6790 v8::Debug::DebugBreak();
6791 v8::Script::Compile(v8::String::New("(function(x){return x+2;})(1);"))->Run();
6792 CHECK(!was_debug_event_called);
6793 CHECK(was_debug_break_called);
6794
6795 TestClientData* data2 = new TestClientData();
6796 expected_break_data = data2;
6797 was_debug_event_called = false;
6798 was_debug_break_called = false;
6799 v8::Debug::DebugBreak();
6800 v8::Debug::DebugBreakForCommand(data2);
6801 v8::Script::Compile(v8::String::New("(function(x){return x+3;})(1);"))->Run();
6802 CHECK(was_debug_event_called);
6803 CHECK(was_debug_break_called);
6804
6805 CHECK_EQ(2, TestClientData::constructor_call_counter);
6806 CHECK_EQ(TestClientData::constructor_call_counter,
6807 TestClientData::destructor_call_counter);
6808
6809 v8::Debug::SetDebugEventListener(NULL);
6810 CheckDebuggerUnloaded();
6811}
6812
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01006813#endif // ENABLE_DEBUGGER_SUPPORT