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