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