Line data Source code
1 : // Copyright 2012 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 : #include <set>
30 :
31 : #include "src/v8.h"
32 :
33 : #include "src/api.h"
34 : #include "src/compilation-cache.h"
35 : #include "src/debug/debug-interface.h"
36 : #include "src/debug/debug.h"
37 : #include "src/deoptimizer.h"
38 : #include "src/frames.h"
39 : #include "src/objects-inl.h"
40 : #include "src/utils.h"
41 : #include "test/cctest/cctest.h"
42 :
43 : using ::v8::internal::EmbeddedVector;
44 : using ::v8::internal::Object;
45 : using ::v8::internal::Handle;
46 : using ::v8::internal::Heap;
47 : using ::v8::internal::JSGlobalProxy;
48 : using ::v8::internal::Code;
49 : using ::v8::internal::Debug;
50 : using ::v8::internal::StackFrame;
51 : using ::v8::internal::StepAction;
52 : using ::v8::internal::StepIn; // From StepAction enum
53 : using ::v8::internal::StepNext; // From StepAction enum
54 : using ::v8::internal::StepOut; // From StepAction enum
55 : using ::v8::internal::Vector;
56 : using ::v8::internal::StrLength;
57 :
58 : // Size of temp buffer for formatting small strings.
59 : #define SMALL_STRING_BUFFER_SIZE 80
60 :
61 : // --- H e l p e r C l a s s e s
62 :
63 :
64 : // Helper class for creating a V8 enviromnent for running tests
65 : class DebugLocalContext {
66 : public:
67 : inline DebugLocalContext(
68 : v8::Isolate* isolate, v8::ExtensionConfiguration* extensions = 0,
69 : v8::Local<v8::ObjectTemplate> global_template =
70 : v8::Local<v8::ObjectTemplate>(),
71 : v8::Local<v8::Value> global_object = v8::Local<v8::Value>())
72 : : scope_(isolate),
73 : context_(v8::Context::New(isolate, extensions, global_template,
74 : global_object)) {
75 : context_->Enter();
76 : }
77 515 : inline DebugLocalContext(
78 : v8::ExtensionConfiguration* extensions = 0,
79 : v8::Local<v8::ObjectTemplate> global_template =
80 : v8::Local<v8::ObjectTemplate>(),
81 : v8::Local<v8::Value> global_object = v8::Local<v8::Value>())
82 : : scope_(CcTest::isolate()),
83 : context_(v8::Context::New(CcTest::isolate(), extensions,
84 1030 : global_template, global_object)) {
85 515 : context_->Enter();
86 515 : }
87 515 : inline ~DebugLocalContext() {
88 515 : context_->Exit();
89 : }
90 : inline v8::Local<v8::Context> context() { return context_; }
91 : inline v8::Context* operator->() { return *context_; }
92 : inline v8::Context* operator*() { return *context_; }
93 475 : inline v8::Isolate* GetIsolate() { return context_->GetIsolate(); }
94 : inline bool IsReady() { return !context_.IsEmpty(); }
95 130 : void ExposeDebug() {
96 260 : v8::internal::Isolate* isolate =
97 130 : reinterpret_cast<v8::internal::Isolate*>(context_->GetIsolate());
98 : v8::internal::Factory* factory = isolate->factory();
99 : // Expose the debug context global object in the global object for testing.
100 130 : CHECK(isolate->debug()->Load());
101 : Handle<v8::internal::Context> debug_context =
102 : isolate->debug()->debug_context();
103 : debug_context->set_security_token(
104 : v8::Utils::OpenHandle(*context_)->security_token());
105 :
106 : Handle<JSGlobalProxy> global(Handle<JSGlobalProxy>::cast(
107 260 : v8::Utils::OpenHandle(*context_->Global())));
108 : Handle<v8::internal::String> debug_string =
109 130 : factory->InternalizeOneByteString(STATIC_CHAR_VECTOR("debug"));
110 : v8::internal::JSObject::SetOwnPropertyIgnoreAttributes(
111 : global, debug_string, handle(debug_context->global_proxy()),
112 260 : v8::internal::DONT_ENUM)
113 260 : .Check();
114 130 : }
115 :
116 : private:
117 : v8::HandleScope scope_;
118 : v8::Local<v8::Context> context_;
119 : };
120 :
121 :
122 : // --- H e l p e r F u n c t i o n s
123 :
124 : // Compile and run the supplied source and return the requested function.
125 500 : static v8::Local<v8::Function> CompileFunction(v8::Isolate* isolate,
126 : const char* source,
127 : const char* function_name) {
128 500 : CompileRunChecked(isolate, source);
129 500 : v8::Local<v8::String> name = v8_str(isolate, function_name);
130 500 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
131 : v8::MaybeLocal<v8::Value> maybe_function =
132 1000 : context->Global()->Get(context, name);
133 500 : return v8::Local<v8::Function>::Cast(maybe_function.ToLocalChecked());
134 : }
135 :
136 :
137 : // Compile and run the supplied source and return the requested function.
138 475 : static v8::Local<v8::Function> CompileFunction(DebugLocalContext* env,
139 : const char* source,
140 : const char* function_name) {
141 475 : return CompileFunction(env->GetIsolate(), source, function_name);
142 : }
143 :
144 1020 : static void SetDebugEventListener(
145 : v8::Isolate* isolate, v8::Debug::EventCallback that,
146 : v8::Local<v8::Value> data = v8::Local<v8::Value>()) {
147 1020 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
148 : i::HandleScope scope(i_isolate);
149 1020 : if (that == nullptr) {
150 480 : i_isolate->debug()->SetDebugDelegate(nullptr, false);
151 : } else {
152 : i::Handle<i::Object> i_data = i_isolate->factory()->undefined_value();
153 540 : if (!data.IsEmpty()) i_data = v8::Utils::OpenHandle(*data);
154 : i::NativeDebugDelegate* delegate =
155 540 : new i::NativeDebugDelegate(i_isolate, that, i_data);
156 540 : i_isolate->debug()->SetDebugDelegate(delegate, true);
157 : }
158 1020 : }
159 :
160 : // Is there any debug info for the function?
161 50 : static bool HasBreakInfo(v8::Local<v8::Function> fun) {
162 : Handle<v8::internal::JSFunction> f =
163 : Handle<v8::internal::JSFunction>::cast(v8::Utils::OpenHandle(*fun));
164 : Handle<v8::internal::SharedFunctionInfo> shared(f->shared());
165 50 : return shared->HasBreakInfo();
166 : }
167 :
168 : // Set a break point in a function with a position relative to function start,
169 : // and return the associated break point number.
170 280 : static int SetBreakPoint(v8::Local<v8::Function> fun, int position) {
171 : i::Handle<i::JSFunction> function =
172 : i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*fun));
173 280 : position += function->shared()->start_position();
174 : static int break_point = 0;
175 280 : v8::internal::Isolate* isolate = function->GetIsolate();
176 : v8::internal::Debug* debug = isolate->debug();
177 : debug->SetBreakPoint(
178 : function,
179 280 : Handle<Object>(v8::internal::Smi::FromInt(++break_point), isolate),
180 560 : &position);
181 280 : return break_point;
182 : }
183 :
184 :
185 : // Set a break point in a function using the Debug object and return the
186 : // associated break point number.
187 10 : static int SetBreakPointFromJS(v8::Isolate* isolate,
188 : const char* function_name,
189 : int line, int position) {
190 : EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
191 : SNPrintF(buffer,
192 : "debug.Debug.setBreakPoint(%s,%d,%d)",
193 10 : function_name, line, position);
194 10 : buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
195 10 : v8::Local<v8::Value> value = CompileRunChecked(isolate, buffer.start());
196 30 : return value->Int32Value(isolate->GetCurrentContext()).FromJust();
197 : }
198 :
199 :
200 : // Set a break point in a script identified by id using the global Debug object.
201 30 : static int SetScriptBreakPointByIdFromJS(v8::Isolate* isolate, int script_id,
202 : int line, int column) {
203 : EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
204 30 : if (column >= 0) {
205 : // Column specified set script break point on precise location.
206 : SNPrintF(buffer,
207 : "debug.Debug.setScriptBreakPointById(%d,%d,%d)",
208 30 : script_id, line, column);
209 : } else {
210 : // Column not specified set script break point on line.
211 : SNPrintF(buffer,
212 : "debug.Debug.setScriptBreakPointById(%d,%d)",
213 0 : script_id, line);
214 : }
215 30 : buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
216 : {
217 30 : v8::TryCatch try_catch(isolate);
218 30 : v8::Local<v8::Value> value = CompileRunChecked(isolate, buffer.start());
219 30 : CHECK(!try_catch.HasCaught());
220 90 : return value->Int32Value(isolate->GetCurrentContext()).FromJust();
221 : }
222 : }
223 :
224 :
225 : // Set a break point in a script identified by name using the global Debug
226 : // object.
227 125 : static int SetScriptBreakPointByNameFromJS(v8::Isolate* isolate,
228 : const char* script_name, int line,
229 : int column) {
230 : EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
231 125 : if (column >= 0) {
232 : // Column specified set script break point on precise location.
233 : SNPrintF(buffer,
234 : "debug.Debug.setScriptBreakPointByName(\"%s\",%d,%d)",
235 70 : script_name, line, column);
236 : } else {
237 : // Column not specified set script break point on line.
238 : SNPrintF(buffer,
239 : "debug.Debug.setScriptBreakPointByName(\"%s\",%d)",
240 55 : script_name, line);
241 : }
242 125 : buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
243 : {
244 125 : v8::TryCatch try_catch(isolate);
245 125 : v8::Local<v8::Value> value = CompileRunChecked(isolate, buffer.start());
246 125 : CHECK(!try_catch.HasCaught());
247 375 : return value->Int32Value(isolate->GetCurrentContext()).FromJust();
248 : }
249 : }
250 :
251 :
252 : // Clear a break point.
253 60 : static void ClearBreakPoint(int break_point) {
254 60 : v8::internal::Isolate* isolate = CcTest::i_isolate();
255 : v8::internal::Debug* debug = isolate->debug();
256 : debug->ClearBreakPoint(
257 60 : Handle<Object>(v8::internal::Smi::FromInt(break_point), isolate));
258 60 : }
259 :
260 :
261 : // Clear a break point using the global Debug object.
262 135 : static void ClearBreakPointFromJS(v8::Isolate* isolate,
263 : int break_point_number) {
264 : EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
265 : SNPrintF(buffer,
266 : "debug.Debug.clearBreakPoint(%d)",
267 135 : break_point_number);
268 135 : buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
269 135 : CompileRunChecked(isolate, buffer.start());
270 135 : }
271 :
272 :
273 5 : static void EnableScriptBreakPointFromJS(v8::Isolate* isolate,
274 : int break_point_number) {
275 : EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
276 : SNPrintF(buffer,
277 : "debug.Debug.enableScriptBreakPoint(%d)",
278 5 : break_point_number);
279 5 : buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
280 5 : CompileRunChecked(isolate, buffer.start());
281 5 : }
282 :
283 :
284 10 : static void DisableScriptBreakPointFromJS(v8::Isolate* isolate,
285 : int break_point_number) {
286 : EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
287 : SNPrintF(buffer,
288 : "debug.Debug.disableScriptBreakPoint(%d)",
289 10 : break_point_number);
290 10 : buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
291 10 : CompileRunChecked(isolate, buffer.start());
292 10 : }
293 :
294 :
295 15 : static void ChangeScriptBreakPointConditionFromJS(v8::Isolate* isolate,
296 : int break_point_number,
297 : const char* condition) {
298 : EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
299 : SNPrintF(buffer,
300 : "debug.Debug.changeScriptBreakPointCondition(%d, \"%s\")",
301 15 : break_point_number, condition);
302 15 : buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
303 15 : CompileRunChecked(isolate, buffer.start());
304 15 : }
305 :
306 :
307 : // Change break on exception.
308 75 : static void ChangeBreakOnException(bool caught, bool uncaught) {
309 75 : v8::internal::Debug* debug = CcTest::i_isolate()->debug();
310 75 : debug->ChangeBreakOnException(v8::internal::BreakException, caught);
311 75 : debug->ChangeBreakOnException(v8::internal::BreakUncaughtException, uncaught);
312 75 : }
313 :
314 :
315 : // Change break on exception using the global Debug object.
316 20 : static void ChangeBreakOnExceptionFromJS(v8::Isolate* isolate, bool caught,
317 : bool uncaught) {
318 20 : if (caught) {
319 10 : CompileRunChecked(isolate, "debug.Debug.setBreakOnException()");
320 : } else {
321 10 : CompileRunChecked(isolate, "debug.Debug.clearBreakOnException()");
322 : }
323 20 : if (uncaught) {
324 10 : CompileRunChecked(isolate, "debug.Debug.setBreakOnUncaughtException()");
325 : } else {
326 10 : CompileRunChecked(isolate, "debug.Debug.clearBreakOnUncaughtException()");
327 : }
328 20 : }
329 :
330 : // Change break on exception using the native API call.
331 : static void ChangeBreakOnExceptionFromAPI(
332 : v8::Isolate* isolate, v8::debug::ExceptionBreakState state) {
333 15 : v8::debug::ChangeBreakOnException(isolate, state);
334 : }
335 :
336 : // Prepare to step to next break location.
337 12340 : static void PrepareStep(StepAction step_action) {
338 12340 : v8::internal::Debug* debug = CcTest::i_isolate()->debug();
339 12340 : debug->PrepareStep(step_action);
340 12340 : }
341 :
342 :
343 40 : static void ClearStepping() { CcTest::i_isolate()->debug()->ClearStepping(); }
344 :
345 :
346 : // This function is in namespace v8::internal to be friend with class
347 : // v8::internal::Debug.
348 : namespace v8 {
349 : namespace internal {
350 :
351 : // Collect the currently debugged functions.
352 25 : Handle<FixedArray> GetDebuggedFunctions() {
353 25 : Debug* debug = CcTest::i_isolate()->debug();
354 :
355 45 : v8::internal::DebugInfoListNode* node = debug->debug_info_list_;
356 :
357 : // Find the number of debugged functions.
358 : int count = 0;
359 70 : while (node) {
360 20 : count++;
361 : node = node->next();
362 : }
363 :
364 : // Allocate array for the debugged functions
365 : Handle<FixedArray> debugged_functions =
366 25 : CcTest::i_isolate()->factory()->NewFixedArray(count);
367 :
368 : // Run through the debug info objects and collect all functions.
369 : count = 0;
370 50 : while (node) {
371 0 : debugged_functions->set(count++, *node->debug_info());
372 : node = node->next();
373 : }
374 :
375 25 : return debugged_functions;
376 : }
377 :
378 :
379 : // Check that the debugger has been fully unloaded.
380 440 : void CheckDebuggerUnloaded() {
381 : // Check that the debugger context is cleared and that there is no debug
382 : // information stored for the debugger.
383 440 : CHECK(CcTest::i_isolate()->debug()->debug_context().is_null());
384 440 : CHECK(!CcTest::i_isolate()->debug()->debug_info_list_);
385 :
386 : // Collect garbage to ensure weak handles are cleared.
387 440 : CcTest::CollectAllGarbage();
388 440 : CcTest::CollectAllGarbage(Heap::kMakeHeapIterableMask);
389 :
390 : // Iterate the heap and check that there are no debugger related objects left.
391 440 : HeapIterator iterator(CcTest::heap());
392 3989796 : for (HeapObject* obj = iterator.next(); obj != nullptr;
393 : obj = iterator.next()) {
394 3989356 : CHECK(!obj->IsDebugInfo());
395 440 : }
396 440 : }
397 :
398 :
399 : } // namespace internal
400 : } // namespace v8
401 :
402 :
403 : // Check that the debugger has been fully unloaded.
404 440 : static void CheckDebuggerUnloaded() { v8::internal::CheckDebuggerUnloaded(); }
405 :
406 : // --- D e b u g E v e n t H a n d l e r s
407 : // ---
408 : // --- The different tests uses a number of debug event handlers.
409 : // ---
410 :
411 :
412 : // Source for the JavaScript function which picks out the function
413 : // name of a frame.
414 : const char* frame_function_name_source =
415 : "function frame_function_name(exec_state, frame_number) {"
416 : " return exec_state.frame(frame_number).func().name();"
417 : "}";
418 : v8::Local<v8::Function> frame_function_name;
419 :
420 :
421 : // Source for the JavaScript function which pick out the name of the
422 : // first argument of a frame.
423 : const char* frame_argument_name_source =
424 : "function frame_argument_name(exec_state, frame_number) {"
425 : " return exec_state.frame(frame_number).argumentName(0);"
426 : "}";
427 : v8::Local<v8::Function> frame_argument_name;
428 :
429 :
430 : // Source for the JavaScript function which pick out the value of the
431 : // first argument of a frame.
432 : const char* frame_argument_value_source =
433 : "function frame_argument_value(exec_state, frame_number) {"
434 : " return exec_state.frame(frame_number).argumentValue(0).value_;"
435 : "}";
436 : v8::Local<v8::Function> frame_argument_value;
437 :
438 :
439 : // Source for the JavaScript function which pick out the name of the
440 : // first argument of a frame.
441 : const char* frame_local_name_source =
442 : "function frame_local_name(exec_state, frame_number) {"
443 : " return exec_state.frame(frame_number).localName(0);"
444 : "}";
445 : v8::Local<v8::Function> frame_local_name;
446 :
447 :
448 : // Source for the JavaScript function which pick out the value of the
449 : // first argument of a frame.
450 : const char* frame_local_value_source =
451 : "function frame_local_value(exec_state, frame_number) {"
452 : " return exec_state.frame(frame_number).localValue(0).value_;"
453 : "}";
454 : v8::Local<v8::Function> frame_local_value;
455 :
456 :
457 : // Source for the JavaScript function which picks out the source line for the
458 : // top frame.
459 : const char* frame_source_line_source =
460 : "function frame_source_line(exec_state) {"
461 : " return exec_state.frame(0).sourceLine();"
462 : "}";
463 : v8::Local<v8::Function> frame_source_line;
464 :
465 :
466 : // Source for the JavaScript function which picks out the source column for the
467 : // top frame.
468 : const char* frame_source_column_source =
469 : "function frame_source_column(exec_state) {"
470 : " return exec_state.frame(0).sourceColumn();"
471 : "}";
472 : v8::Local<v8::Function> frame_source_column;
473 :
474 :
475 : // Source for the JavaScript function which picks out the script name for the
476 : // top frame.
477 : const char* frame_script_name_source =
478 : "function frame_script_name(exec_state) {"
479 : " return exec_state.frame(0).func().script().name();"
480 : "}";
481 : v8::Local<v8::Function> frame_script_name;
482 :
483 :
484 : // Source for the JavaScript function which returns the number of frames.
485 : static const char* frame_count_source =
486 : "function frame_count(exec_state) {"
487 : " return exec_state.frameCount();"
488 : "}";
489 : v8::Local<v8::Function> frame_count;
490 :
491 :
492 : // Global variable to store the last function hit - used by some tests.
493 : char last_function_hit[80];
494 :
495 : // Global variable to store the name for last script hit - used by some tests.
496 : char last_script_name_hit[80];
497 :
498 : // Global variables to store the last source position - used by some tests.
499 : int last_source_line = -1;
500 : int last_source_column = -1;
501 :
502 : // Debug event handler which counts the break points which have been hit.
503 : int break_point_hit_count = 0;
504 : int break_point_hit_count_deoptimize = 0;
505 1175 : static void DebugEventBreakPointHitCount(
506 : const v8::Debug::EventDetails& event_details) {
507 1175 : v8::DebugEvent event = event_details.GetEvent();
508 1175 : v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
509 1175 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
510 1175 : v8::internal::Isolate* isolate = CcTest::i_isolate();
511 1175 : Debug* debug = isolate->debug();
512 : // When hitting a debug event listener there must be a break set.
513 1175 : CHECK_NE(debug->break_id(), 0);
514 :
515 : // Count the number of breaks.
516 1175 : if (event == v8::Break) {
517 600 : break_point_hit_count++;
518 600 : if (!frame_function_name.IsEmpty()) {
519 : // Get the name of the function.
520 : const int argc = 2;
521 : v8::Local<v8::Value> argv[argc] = {
522 20 : exec_state, v8::Integer::New(CcTest::isolate(), 0)};
523 : v8::Local<v8::Value> result =
524 20 : frame_function_name->Call(context, exec_state, argc, argv)
525 20 : .ToLocalChecked();
526 20 : if (result->IsUndefined()) {
527 0 : last_function_hit[0] = '\0';
528 : } else {
529 20 : CHECK(result->IsString());
530 : v8::Local<v8::String> function_name(result.As<v8::String>());
531 20 : function_name->WriteUtf8(last_function_hit);
532 : }
533 : }
534 :
535 600 : if (!frame_source_line.IsEmpty()) {
536 : // Get the source line.
537 : const int argc = 1;
538 : v8::Local<v8::Value> argv[argc] = {exec_state};
539 : v8::Local<v8::Value> result =
540 10 : frame_source_line->Call(context, exec_state, argc, argv)
541 10 : .ToLocalChecked();
542 10 : CHECK(result->IsNumber());
543 20 : last_source_line = result->Int32Value(context).FromJust();
544 : }
545 :
546 600 : if (!frame_source_column.IsEmpty()) {
547 : // Get the source column.
548 : const int argc = 1;
549 : v8::Local<v8::Value> argv[argc] = {exec_state};
550 : v8::Local<v8::Value> result =
551 10 : frame_source_column->Call(context, exec_state, argc, argv)
552 10 : .ToLocalChecked();
553 10 : CHECK(result->IsNumber());
554 20 : last_source_column = result->Int32Value(context).FromJust();
555 : }
556 :
557 600 : if (!frame_script_name.IsEmpty()) {
558 : // Get the script name of the function script.
559 : const int argc = 1;
560 : v8::Local<v8::Value> argv[argc] = {exec_state};
561 : v8::Local<v8::Value> result =
562 20 : frame_script_name->Call(context, exec_state, argc, argv)
563 20 : .ToLocalChecked();
564 20 : if (result->IsUndefined()) {
565 0 : last_script_name_hit[0] = '\0';
566 : } else {
567 20 : CHECK(result->IsString());
568 : v8::Local<v8::String> script_name(result.As<v8::String>());
569 20 : script_name->WriteUtf8(last_script_name_hit);
570 : }
571 : }
572 :
573 : // Perform a full deoptimization when the specified number of
574 : // breaks have been hit.
575 600 : if (break_point_hit_count == break_point_hit_count_deoptimize) {
576 0 : i::Deoptimizer::DeoptimizeAll(isolate);
577 : }
578 : }
579 1175 : }
580 :
581 :
582 : // Debug event handler which counts a number of events and collects the stack
583 : // height if there is a function compiled for that.
584 : int exception_hit_count = 0;
585 : int uncaught_exception_hit_count = 0;
586 : int last_js_stack_height = -1;
587 : v8::Local<v8::Function> debug_event_listener_callback;
588 : int debug_event_listener_callback_result;
589 :
590 : static void DebugEventCounterClear() {
591 75 : break_point_hit_count = 0;
592 75 : exception_hit_count = 0;
593 75 : uncaught_exception_hit_count = 0;
594 : }
595 :
596 280 : static void DebugEventCounter(
597 : const v8::Debug::EventDetails& event_details) {
598 280 : v8::Isolate::AllowJavascriptExecutionScope allow_script(CcTest::isolate());
599 280 : v8::DebugEvent event = event_details.GetEvent();
600 280 : v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
601 280 : v8::Local<v8::Object> event_data = event_details.GetEventData();
602 280 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
603 280 : v8::internal::Debug* debug = CcTest::i_isolate()->debug();
604 :
605 : // When hitting a debug event listener there must be a break set.
606 280 : CHECK_NE(debug->break_id(), 0);
607 :
608 : // Count the number of breaks.
609 280 : if (event == v8::Break) {
610 20 : break_point_hit_count++;
611 260 : } else if (event == v8::Exception) {
612 160 : exception_hit_count++;
613 :
614 : // Check whether the exception was uncaught.
615 160 : v8::Local<v8::String> fun_name = v8_str(CcTest::isolate(), "uncaught");
616 : v8::Local<v8::Function> fun = v8::Local<v8::Function>::Cast(
617 320 : event_data->Get(context, fun_name).ToLocalChecked());
618 : v8::Local<v8::Value> result =
619 320 : fun->Call(context, event_data, 0, nullptr).ToLocalChecked();
620 160 : if (result->IsTrue()) {
621 135 : uncaught_exception_hit_count++;
622 : }
623 : }
624 :
625 : // Collect the JavsScript stack height if the function frame_count is
626 : // compiled.
627 280 : if (!frame_count.IsEmpty()) {
628 : static const int kArgc = 1;
629 : v8::Local<v8::Value> argv[kArgc] = {exec_state};
630 : // Using exec_state as receiver is just to have a receiver.
631 : v8::Local<v8::Value> result =
632 80 : frame_count->Call(context, exec_state, kArgc, argv).ToLocalChecked();
633 80 : last_js_stack_height = result->Int32Value(context).FromJust();
634 : }
635 :
636 : // Run callback from DebugEventListener and check the result.
637 280 : if (!debug_event_listener_callback.IsEmpty()) {
638 : v8::Local<v8::Value> result =
639 0 : debug_event_listener_callback->Call(context, event_data, 0, nullptr)
640 0 : .ToLocalChecked();
641 0 : CHECK(!result.IsEmpty());
642 0 : CHECK_EQ(debug_event_listener_callback_result,
643 : result->Int32Value(context).FromJust());
644 280 : }
645 280 : }
646 :
647 :
648 : // Debug event handler which evaluates a number of expressions when a break
649 : // point is hit. Each evaluated expression is compared with an expected value.
650 : // For this debug event handler to work the following two global varaibles
651 : // must be initialized.
652 : // checks: An array of expressions and expected results
653 : // evaluate_check_function: A JavaScript function (see below)
654 :
655 : // Structure for holding checks to do.
656 : struct EvaluateCheck {
657 : const char* expr; // An expression to evaluate when a break point is hit.
658 : v8::Local<v8::Value> expected; // The expected result.
659 : };
660 :
661 :
662 : // Array of checks to do.
663 : struct EvaluateCheck* checks = nullptr;
664 : // Source for The JavaScript function which can do the evaluation when a break
665 : // point is hit.
666 : const char* evaluate_check_source =
667 : "function evaluate_check(exec_state, expr, expected) {"
668 : " return exec_state.frame(0).evaluate(expr).value() === expected;"
669 : "}";
670 : v8::Local<v8::Function> evaluate_check_function;
671 :
672 : // The actual debug event described by the longer comment above.
673 75 : static void DebugEventEvaluate(
674 : const v8::Debug::EventDetails& event_details) {
675 75 : v8::DebugEvent event = event_details.GetEvent();
676 75 : v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
677 75 : v8::Isolate* isolate = CcTest::isolate();
678 75 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
679 75 : v8::internal::Debug* debug = CcTest::i_isolate()->debug();
680 : // When hitting a debug event listener there must be a break set.
681 75 : CHECK_NE(debug->break_id(), 0);
682 :
683 75 : if (event == v8::Break) {
684 20 : break_point_hit_count++;
685 60 : for (int i = 0; checks[i].expr != nullptr; i++) {
686 : const int argc = 3;
687 40 : v8::Local<v8::String> string = v8_str(isolate, checks[i].expr);
688 : v8::Local<v8::Value> argv[argc] = {exec_state, string,
689 40 : checks[i].expected};
690 : v8::Local<v8::Value> result =
691 40 : evaluate_check_function->Call(context, exec_state, argc, argv)
692 40 : .ToLocalChecked();
693 40 : if (!result->IsTrue()) {
694 0 : v8::String::Utf8Value utf8(isolate, checks[i].expected);
695 0 : V8_Fatal(__FILE__, __LINE__, "%s != %s", checks[i].expr, *utf8);
696 : }
697 : }
698 : }
699 75 : }
700 :
701 :
702 : // This debug event listener removes a breakpoint in a function
703 : int debug_event_remove_break_point = 0;
704 5 : static void DebugEventRemoveBreakPoint(
705 : const v8::Debug::EventDetails& event_details) {
706 5 : v8::DebugEvent event = event_details.GetEvent();
707 5 : v8::Local<v8::Value> data = event_details.GetCallbackData();
708 5 : v8::internal::Debug* debug = CcTest::i_isolate()->debug();
709 : // When hitting a debug event listener there must be a break set.
710 5 : CHECK_NE(debug->break_id(), 0);
711 :
712 5 : if (event == v8::Break) {
713 5 : break_point_hit_count++;
714 5 : CHECK(data->IsFunction());
715 5 : ClearBreakPoint(debug_event_remove_break_point);
716 : }
717 5 : }
718 :
719 :
720 : // Debug event handler which counts break points hit and performs a step
721 : // afterwards.
722 : StepAction step_action = StepIn; // Step action to perform when stepping.
723 12055 : static void DebugEventStep(
724 : const v8::Debug::EventDetails& event_details) {
725 12055 : v8::DebugEvent event = event_details.GetEvent();
726 12055 : v8::internal::Debug* debug = CcTest::i_isolate()->debug();
727 : // When hitting a debug event listener there must be a break set.
728 12055 : CHECK_NE(debug->break_id(), 0);
729 :
730 12055 : if (event == v8::Break) {
731 11960 : break_point_hit_count++;
732 11960 : PrepareStep(step_action);
733 : }
734 12055 : }
735 :
736 :
737 : // Debug event handler which counts break points hit and performs a step
738 : // afterwards. For each call the expected function is checked.
739 : // For this debug event handler to work the following two global varaibles
740 : // must be initialized.
741 : // expected_step_sequence: An array of the expected function call sequence.
742 : // frame_function_name: A JavaScript function (see below).
743 :
744 : // String containing the expected function call sequence. Note: this only works
745 : // if functions have name length of one.
746 : const char* expected_step_sequence = nullptr;
747 :
748 : // The actual debug event described by the longer comment above.
749 385 : static void DebugEventStepSequence(
750 : const v8::Debug::EventDetails& event_details) {
751 385 : v8::DebugEvent event = event_details.GetEvent();
752 385 : v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
753 385 : v8::internal::Debug* debug = CcTest::i_isolate()->debug();
754 : // When hitting a debug event listener there must be a break set.
755 385 : CHECK_NE(debug->break_id(), 0);
756 :
757 385 : if (event == v8::Break || event == v8::Exception) {
758 : // Check that the current function is the expected.
759 700 : CHECK(break_point_hit_count <
760 : StrLength(expected_step_sequence));
761 : const int argc = 2;
762 : v8::Local<v8::Value> argv[argc] = {exec_state,
763 350 : v8::Integer::New(CcTest::isolate(), 0)};
764 350 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
765 : v8::Local<v8::Value> result =
766 350 : frame_function_name->Call(context, exec_state, argc, argv)
767 350 : .ToLocalChecked();
768 350 : CHECK(result->IsString());
769 : v8::String::Utf8Value function_name(
770 700 : CcTest::isolate(), result->ToString(context).ToLocalChecked());
771 700 : CHECK_EQ(1, StrLength(*function_name));
772 350 : CHECK_EQ((*function_name)[0],
773 : expected_step_sequence[break_point_hit_count]);
774 :
775 : // Perform step.
776 350 : break_point_hit_count++;
777 350 : PrepareStep(step_action);
778 : }
779 385 : }
780 :
781 :
782 : // Debug event handler which performs a garbage collection.
783 465 : static void DebugEventBreakPointCollectGarbage(
784 : const v8::Debug::EventDetails& event_details) {
785 465 : v8::DebugEvent event = event_details.GetEvent();
786 465 : v8::internal::Debug* debug = CcTest::i_isolate()->debug();
787 : // When hitting a debug event listener there must be a break set.
788 465 : CHECK_NE(debug->break_id(), 0);
789 :
790 : // Perform a garbage collection when break point is hit and continue. Based
791 : // on the number of break points hit either scavenge or mark compact
792 : // collector is used.
793 465 : if (event == v8::Break) {
794 420 : break_point_hit_count++;
795 420 : if (break_point_hit_count % 2 == 0) {
796 : // Scavenge.
797 205 : CcTest::CollectGarbage(v8::internal::NEW_SPACE);
798 : } else {
799 : // Mark sweep compact.
800 215 : CcTest::CollectAllGarbage();
801 : }
802 : }
803 465 : }
804 :
805 :
806 : // Debug event handler which re-issues a debug break and calls the garbage
807 : // collector to have the heap verified.
808 100 : static void DebugEventBreak(
809 : const v8::Debug::EventDetails& event_details) {
810 100 : v8::DebugEvent event = event_details.GetEvent();
811 100 : v8::internal::Debug* debug = CcTest::i_isolate()->debug();
812 : // When hitting a debug event listener there must be a break set.
813 100 : CHECK_NE(debug->break_id(), 0);
814 :
815 100 : if (event == v8::Break) {
816 : // Count the number of breaks.
817 80 : break_point_hit_count++;
818 :
819 : // Run the garbage collector to enforce heap verification if option
820 : // --verify-heap is set.
821 80 : CcTest::CollectGarbage(v8::internal::NEW_SPACE);
822 :
823 : // Set the break flag again to come back here as soon as possible.
824 80 : v8::debug::DebugBreak(CcTest::isolate());
825 : }
826 100 : }
827 :
828 :
829 : // Debug event handler which re-issues a debug break until a limit has been
830 : // reached.
831 : int max_break_point_hit_count = 0;
832 : bool terminate_after_max_break_point_hit = false;
833 12945 : static void DebugEventBreakMax(
834 : const v8::Debug::EventDetails& event_details) {
835 12945 : v8::DebugEvent event = event_details.GetEvent();
836 12945 : v8::Isolate* v8_isolate = CcTest::isolate();
837 12945 : v8::internal::Isolate* isolate = CcTest::i_isolate();
838 12945 : v8::internal::Debug* debug = isolate->debug();
839 : // When hitting a debug event listener there must be a break set.
840 12945 : CHECK_NE(debug->break_id(), 0);
841 :
842 12945 : if (event == v8::Break) {
843 10905 : if (break_point_hit_count < max_break_point_hit_count) {
844 : // Count the number of breaks.
845 9915 : break_point_hit_count++;
846 :
847 : // Set the break flag again to come back here as soon as possible.
848 9915 : v8::debug::DebugBreak(v8_isolate);
849 :
850 990 : } else if (terminate_after_max_break_point_hit) {
851 : // Terminate execution after the last break if requested.
852 990 : v8_isolate->TerminateExecution();
853 : }
854 :
855 : // Perform a full deoptimization when the specified number of
856 : // breaks have been hit.
857 10905 : if (break_point_hit_count == break_point_hit_count_deoptimize) {
858 990 : i::Deoptimizer::DeoptimizeAll(isolate);
859 : }
860 : }
861 12945 : }
862 :
863 :
864 : // --- M e s s a g e C a l l b a c k
865 :
866 :
867 : // Message callback which counts the number of messages.
868 : int message_callback_count = 0;
869 :
870 : static void MessageCallbackCountClear() {
871 65 : message_callback_count = 0;
872 : }
873 :
874 140 : static void MessageCallbackCount(v8::Local<v8::Message> message,
875 : v8::Local<v8::Value> data) {
876 140 : message_callback_count++;
877 140 : }
878 :
879 :
880 : // --- T h e A c t u a l T e s t s
881 :
882 : // Test that the debug info in the VM is in sync with the functions being
883 : // debugged.
884 23723 : TEST(DebugInfo) {
885 5 : DebugLocalContext env;
886 10 : v8::HandleScope scope(env->GetIsolate());
887 : // Create a couple of functions for the test.
888 : v8::Local<v8::Function> foo =
889 5 : CompileFunction(&env, "function foo(){}", "foo");
890 : v8::Local<v8::Function> bar =
891 5 : CompileFunction(&env, "function bar(){}", "bar");
892 : // Initially no functions are debugged.
893 10 : CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
894 5 : CHECK(!HasBreakInfo(foo));
895 5 : CHECK(!HasBreakInfo(bar));
896 5 : EnableDebugger(env->GetIsolate());
897 : // One function (foo) is debugged.
898 5 : int bp1 = SetBreakPoint(foo, 0);
899 10 : CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
900 5 : CHECK(HasBreakInfo(foo));
901 5 : CHECK(!HasBreakInfo(bar));
902 : // Two functions are debugged.
903 5 : int bp2 = SetBreakPoint(bar, 0);
904 10 : CHECK_EQ(2, v8::internal::GetDebuggedFunctions()->length());
905 5 : CHECK(HasBreakInfo(foo));
906 5 : CHECK(HasBreakInfo(bar));
907 : // One function (bar) is debugged.
908 5 : ClearBreakPoint(bp1);
909 10 : CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
910 5 : CHECK(!HasBreakInfo(foo));
911 5 : CHECK(HasBreakInfo(bar));
912 : // No functions are debugged.
913 5 : ClearBreakPoint(bp2);
914 5 : DisableDebugger(env->GetIsolate());
915 10 : CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
916 5 : CHECK(!HasBreakInfo(foo));
917 5 : CHECK(!HasBreakInfo(bar));
918 5 : }
919 :
920 :
921 : // Test that a break point can be set at an IC store location.
922 23723 : TEST(BreakPointICStore) {
923 5 : break_point_hit_count = 0;
924 5 : DebugLocalContext env;
925 10 : v8::HandleScope scope(env->GetIsolate());
926 :
927 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
928 : v8::Local<v8::Function> foo =
929 5 : CompileFunction(&env, "function foo(){bar=0;}", "foo");
930 :
931 : // Run without breakpoints.
932 15 : foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
933 5 : CHECK_EQ(0, break_point_hit_count);
934 :
935 : // Run with breakpoint
936 5 : int bp = SetBreakPoint(foo, 0);
937 15 : foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
938 5 : CHECK_EQ(1, break_point_hit_count);
939 15 : foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
940 5 : CHECK_EQ(2, break_point_hit_count);
941 :
942 : // Run without breakpoints.
943 5 : ClearBreakPoint(bp);
944 15 : foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
945 5 : CHECK_EQ(2, break_point_hit_count);
946 :
947 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
948 : CheckDebuggerUnloaded();
949 5 : }
950 :
951 :
952 : // Test that a break point can be set at an IC load location.
953 23723 : TEST(BreakPointICLoad) {
954 5 : break_point_hit_count = 0;
955 5 : DebugLocalContext env;
956 10 : v8::HandleScope scope(env->GetIsolate());
957 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
958 :
959 5 : CompileRunChecked(env->GetIsolate(), "bar=1");
960 : v8::Local<v8::Function> foo =
961 5 : CompileFunction(&env, "function foo(){var x=bar;}", "foo");
962 :
963 : // Run without breakpoints.
964 15 : foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
965 5 : CHECK_EQ(0, break_point_hit_count);
966 :
967 : // Run with breakpoint.
968 5 : int bp = SetBreakPoint(foo, 0);
969 15 : foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
970 5 : CHECK_EQ(1, break_point_hit_count);
971 15 : foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
972 5 : CHECK_EQ(2, break_point_hit_count);
973 :
974 : // Run without breakpoints.
975 5 : ClearBreakPoint(bp);
976 15 : foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
977 5 : CHECK_EQ(2, break_point_hit_count);
978 :
979 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
980 : CheckDebuggerUnloaded();
981 5 : }
982 :
983 :
984 : // Test that a break point can be set at an IC call location.
985 23723 : TEST(BreakPointICCall) {
986 5 : break_point_hit_count = 0;
987 5 : DebugLocalContext env;
988 10 : v8::HandleScope scope(env->GetIsolate());
989 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
990 5 : CompileRunChecked(env->GetIsolate(), "function bar(){}");
991 : v8::Local<v8::Function> foo =
992 5 : CompileFunction(&env, "function foo(){bar();}", "foo");
993 :
994 : // Run without breakpoints.
995 15 : foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
996 5 : CHECK_EQ(0, break_point_hit_count);
997 :
998 : // Run with breakpoint
999 5 : int bp = SetBreakPoint(foo, 0);
1000 15 : foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
1001 5 : CHECK_EQ(1, break_point_hit_count);
1002 15 : foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
1003 5 : CHECK_EQ(2, break_point_hit_count);
1004 :
1005 : // Run without breakpoints.
1006 5 : ClearBreakPoint(bp);
1007 15 : foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
1008 5 : CHECK_EQ(2, break_point_hit_count);
1009 :
1010 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
1011 : CheckDebuggerUnloaded();
1012 5 : }
1013 :
1014 :
1015 : // Test that a break point can be set at an IC call location and survive a GC.
1016 23723 : TEST(BreakPointICCallWithGC) {
1017 5 : break_point_hit_count = 0;
1018 5 : DebugLocalContext env;
1019 10 : v8::HandleScope scope(env->GetIsolate());
1020 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointCollectGarbage);
1021 5 : CompileRunChecked(env->GetIsolate(), "function bar(){return 1;}");
1022 : v8::Local<v8::Function> foo =
1023 5 : CompileFunction(&env, "function foo(){return bar();}", "foo");
1024 5 : v8::Local<v8::Context> context = env.context();
1025 :
1026 : // Run without breakpoints.
1027 20 : CHECK_EQ(1, foo->Call(context, env->Global(), 0, nullptr)
1028 : .ToLocalChecked()
1029 : ->Int32Value(context)
1030 : .FromJust());
1031 5 : CHECK_EQ(0, break_point_hit_count);
1032 :
1033 : // Run with breakpoint.
1034 5 : int bp = SetBreakPoint(foo, 0);
1035 20 : CHECK_EQ(1, foo->Call(context, env->Global(), 0, nullptr)
1036 : .ToLocalChecked()
1037 : ->Int32Value(context)
1038 : .FromJust());
1039 5 : CHECK_EQ(1, break_point_hit_count);
1040 20 : CHECK_EQ(1, foo->Call(context, env->Global(), 0, nullptr)
1041 : .ToLocalChecked()
1042 : ->Int32Value(context)
1043 : .FromJust());
1044 5 : CHECK_EQ(2, break_point_hit_count);
1045 :
1046 : // Run without breakpoints.
1047 5 : ClearBreakPoint(bp);
1048 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1049 5 : CHECK_EQ(2, break_point_hit_count);
1050 :
1051 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
1052 : CheckDebuggerUnloaded();
1053 5 : }
1054 :
1055 :
1056 : // Test that a break point can be set at an IC call location and survive a GC.
1057 23723 : TEST(BreakPointConstructCallWithGC) {
1058 5 : break_point_hit_count = 0;
1059 5 : DebugLocalContext env;
1060 10 : v8::HandleScope scope(env->GetIsolate());
1061 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointCollectGarbage);
1062 5 : CompileRunChecked(env->GetIsolate(), "function bar(){ this.x = 1;}");
1063 : v8::Local<v8::Function> foo =
1064 5 : CompileFunction(&env, "function foo(){return new bar(1).x;}", "foo");
1065 5 : v8::Local<v8::Context> context = env.context();
1066 :
1067 : // Run without breakpoints.
1068 20 : CHECK_EQ(1, foo->Call(context, env->Global(), 0, nullptr)
1069 : .ToLocalChecked()
1070 : ->Int32Value(context)
1071 : .FromJust());
1072 5 : CHECK_EQ(0, break_point_hit_count);
1073 :
1074 : // Run with breakpoint.
1075 5 : int bp = SetBreakPoint(foo, 0);
1076 20 : CHECK_EQ(1, foo->Call(context, env->Global(), 0, nullptr)
1077 : .ToLocalChecked()
1078 : ->Int32Value(context)
1079 : .FromJust());
1080 5 : CHECK_EQ(1, break_point_hit_count);
1081 20 : CHECK_EQ(1, foo->Call(context, env->Global(), 0, nullptr)
1082 : .ToLocalChecked()
1083 : ->Int32Value(context)
1084 : .FromJust());
1085 5 : CHECK_EQ(2, break_point_hit_count);
1086 :
1087 : // Run without breakpoints.
1088 5 : ClearBreakPoint(bp);
1089 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1090 5 : CHECK_EQ(2, break_point_hit_count);
1091 :
1092 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
1093 : CheckDebuggerUnloaded();
1094 5 : }
1095 :
1096 :
1097 : // Test that a break point can be set at a return store location.
1098 23723 : TEST(BreakPointReturn) {
1099 5 : break_point_hit_count = 0;
1100 5 : DebugLocalContext env;
1101 10 : v8::HandleScope scope(env->GetIsolate());
1102 :
1103 : // Create a functions for checking the source line and column when hitting
1104 : // a break point.
1105 : frame_source_line = CompileFunction(&env,
1106 : frame_source_line_source,
1107 5 : "frame_source_line");
1108 : frame_source_column = CompileFunction(&env,
1109 : frame_source_column_source,
1110 5 : "frame_source_column");
1111 :
1112 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
1113 : v8::Local<v8::Function> foo =
1114 5 : CompileFunction(&env, "function foo(){}", "foo");
1115 5 : v8::Local<v8::Context> context = env.context();
1116 :
1117 : // Run without breakpoints.
1118 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1119 5 : CHECK_EQ(0, break_point_hit_count);
1120 :
1121 : // Run with breakpoint
1122 5 : int bp = SetBreakPoint(foo, 0);
1123 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1124 5 : CHECK_EQ(1, break_point_hit_count);
1125 5 : CHECK_EQ(0, last_source_line);
1126 5 : CHECK_EQ(15, last_source_column);
1127 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1128 5 : CHECK_EQ(2, break_point_hit_count);
1129 5 : CHECK_EQ(0, last_source_line);
1130 5 : CHECK_EQ(15, last_source_column);
1131 :
1132 : // Run without breakpoints.
1133 5 : ClearBreakPoint(bp);
1134 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1135 5 : CHECK_EQ(2, break_point_hit_count);
1136 :
1137 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
1138 : CheckDebuggerUnloaded();
1139 5 : }
1140 :
1141 :
1142 25 : static void CallWithBreakPoints(v8::Local<v8::Context> context,
1143 : v8::Local<v8::Object> recv,
1144 : v8::Local<v8::Function> f,
1145 : int break_point_count, int call_count) {
1146 25 : break_point_hit_count = 0;
1147 450 : for (int i = 0; i < call_count; i++) {
1148 800 : f->Call(context, recv, 0, nullptr).ToLocalChecked();
1149 400 : CHECK_EQ((i + 1) * break_point_count, break_point_hit_count);
1150 : }
1151 25 : }
1152 :
1153 :
1154 : // Test GC during break point processing.
1155 23723 : TEST(GCDuringBreakPointProcessing) {
1156 5 : break_point_hit_count = 0;
1157 5 : DebugLocalContext env;
1158 10 : v8::HandleScope scope(env->GetIsolate());
1159 5 : v8::Local<v8::Context> context = env.context();
1160 :
1161 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointCollectGarbage);
1162 : v8::Local<v8::Function> foo;
1163 :
1164 : // Test IC store break point with garbage collection.
1165 5 : foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1166 5 : SetBreakPoint(foo, 0);
1167 5 : CallWithBreakPoints(context, env->Global(), foo, 1, 10);
1168 :
1169 : // Test IC load break point with garbage collection.
1170 5 : foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1171 5 : SetBreakPoint(foo, 0);
1172 5 : CallWithBreakPoints(context, env->Global(), foo, 1, 10);
1173 :
1174 : // Test IC call break point with garbage collection.
1175 5 : foo = CompileFunction(&env, "function bar(){};function foo(){bar();}", "foo");
1176 5 : SetBreakPoint(foo, 0);
1177 5 : CallWithBreakPoints(context, env->Global(), foo, 1, 10);
1178 :
1179 : // Test return break point with garbage collection.
1180 5 : foo = CompileFunction(&env, "function foo(){}", "foo");
1181 5 : SetBreakPoint(foo, 0);
1182 5 : CallWithBreakPoints(context, env->Global(), foo, 1, 25);
1183 :
1184 : // Test debug break slot break point with garbage collection.
1185 5 : foo = CompileFunction(&env, "function foo(){var a;}", "foo");
1186 5 : SetBreakPoint(foo, 0);
1187 5 : CallWithBreakPoints(context, env->Global(), foo, 1, 25);
1188 :
1189 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
1190 : CheckDebuggerUnloaded();
1191 5 : }
1192 :
1193 :
1194 : // Call the function three times with different garbage collections in between
1195 : // and make sure that the break point survives.
1196 25 : static void CallAndGC(v8::Local<v8::Context> context,
1197 : v8::Local<v8::Object> recv, v8::Local<v8::Function> f) {
1198 25 : break_point_hit_count = 0;
1199 :
1200 125 : for (int i = 0; i < 3; i++) {
1201 : // Call function.
1202 150 : f->Call(context, recv, 0, nullptr).ToLocalChecked();
1203 75 : CHECK_EQ(1 + i * 3, break_point_hit_count);
1204 :
1205 : // Scavenge and call function.
1206 75 : CcTest::CollectGarbage(v8::internal::NEW_SPACE);
1207 150 : f->Call(context, recv, 0, nullptr).ToLocalChecked();
1208 75 : CHECK_EQ(2 + i * 3, break_point_hit_count);
1209 :
1210 : // Mark sweep (and perhaps compact) and call function.
1211 75 : CcTest::CollectAllGarbage();
1212 150 : f->Call(context, recv, 0, nullptr).ToLocalChecked();
1213 75 : CHECK_EQ(3 + i * 3, break_point_hit_count);
1214 : }
1215 25 : }
1216 :
1217 :
1218 : // Test that a break point can be set at a return store location.
1219 23723 : TEST(BreakPointSurviveGC) {
1220 5 : break_point_hit_count = 0;
1221 5 : DebugLocalContext env;
1222 10 : v8::HandleScope scope(env->GetIsolate());
1223 5 : v8::Local<v8::Context> context = env.context();
1224 :
1225 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
1226 : v8::Local<v8::Function> foo;
1227 :
1228 : // Test IC store break point with garbage collection.
1229 : {
1230 5 : CompileFunction(&env, "function foo(){}", "foo");
1231 5 : foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1232 5 : SetBreakPoint(foo, 0);
1233 : }
1234 5 : CallAndGC(context, env->Global(), foo);
1235 :
1236 : // Test IC load break point with garbage collection.
1237 : {
1238 5 : CompileFunction(&env, "function foo(){}", "foo");
1239 5 : foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1240 5 : SetBreakPoint(foo, 0);
1241 : }
1242 5 : CallAndGC(context, env->Global(), foo);
1243 :
1244 : // Test IC call break point with garbage collection.
1245 : {
1246 5 : CompileFunction(&env, "function foo(){}", "foo");
1247 : foo = CompileFunction(&env,
1248 : "function bar(){};function foo(){bar();}",
1249 5 : "foo");
1250 5 : SetBreakPoint(foo, 0);
1251 : }
1252 5 : CallAndGC(context, env->Global(), foo);
1253 :
1254 : // Test return break point with garbage collection.
1255 : {
1256 5 : CompileFunction(&env, "function foo(){}", "foo");
1257 5 : foo = CompileFunction(&env, "function foo(){}", "foo");
1258 5 : SetBreakPoint(foo, 0);
1259 : }
1260 5 : CallAndGC(context, env->Global(), foo);
1261 :
1262 : // Test non IC break point with garbage collection.
1263 : {
1264 5 : CompileFunction(&env, "function foo(){}", "foo");
1265 5 : foo = CompileFunction(&env, "function foo(){var bar=0;}", "foo");
1266 5 : SetBreakPoint(foo, 0);
1267 : }
1268 5 : CallAndGC(context, env->Global(), foo);
1269 :
1270 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
1271 : CheckDebuggerUnloaded();
1272 5 : }
1273 :
1274 :
1275 : // Test that break points can be set using the global Debug object.
1276 23723 : TEST(BreakPointThroughJavaScript) {
1277 5 : break_point_hit_count = 0;
1278 5 : DebugLocalContext env;
1279 5 : v8::Isolate* isolate = env->GetIsolate();
1280 10 : v8::HandleScope scope(isolate);
1281 5 : v8::Local<v8::Context> context = env.context();
1282 5 : env.ExposeDebug();
1283 :
1284 5 : SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
1285 5 : CompileRunChecked(isolate, "function bar(){}");
1286 5 : CompileFunction(isolate, "function foo(){bar();bar();}", "foo");
1287 : // 012345678901234567890
1288 : // 1 2
1289 : // Break points are set at position 3 and 9
1290 5 : v8::Local<v8::String> source = v8_str(env->GetIsolate(), "foo()");
1291 : v8::Local<v8::Script> foo =
1292 5 : v8::Script::Compile(context, source).ToLocalChecked();
1293 :
1294 5 : CHECK_EQ(0, break_point_hit_count);
1295 :
1296 : // Run with one breakpoint
1297 5 : int bp1 = SetBreakPointFromJS(env->GetIsolate(), "foo", 0, 3);
1298 5 : foo->Run(context).ToLocalChecked();
1299 5 : CHECK_EQ(1, break_point_hit_count);
1300 5 : foo->Run(context).ToLocalChecked();
1301 5 : CHECK_EQ(2, break_point_hit_count);
1302 :
1303 : // Run with two breakpoints
1304 5 : int bp2 = SetBreakPointFromJS(env->GetIsolate(), "foo", 0, 9);
1305 5 : foo->Run(context).ToLocalChecked();
1306 5 : CHECK_EQ(4, break_point_hit_count);
1307 5 : foo->Run(context).ToLocalChecked();
1308 5 : CHECK_EQ(6, break_point_hit_count);
1309 :
1310 : // Run with one breakpoint
1311 5 : ClearBreakPointFromJS(env->GetIsolate(), bp2);
1312 5 : foo->Run(context).ToLocalChecked();
1313 5 : CHECK_EQ(7, break_point_hit_count);
1314 5 : foo->Run(context).ToLocalChecked();
1315 5 : CHECK_EQ(8, break_point_hit_count);
1316 :
1317 : // Run without breakpoints.
1318 5 : ClearBreakPointFromJS(env->GetIsolate(), bp1);
1319 5 : foo->Run(context).ToLocalChecked();
1320 5 : CHECK_EQ(8, break_point_hit_count);
1321 :
1322 5 : SetDebugEventListener(isolate, nullptr);
1323 : CheckDebuggerUnloaded();
1324 :
1325 : // Make sure that the break point numbers are consecutive.
1326 5 : CHECK_EQ(1, bp1);
1327 5 : CHECK_EQ(2, bp2);
1328 5 : }
1329 :
1330 :
1331 : // Test that break points on scripts identified by name can be set using the
1332 : // global Debug object.
1333 23723 : TEST(ScriptBreakPointByNameThroughJavaScript) {
1334 5 : break_point_hit_count = 0;
1335 5 : DebugLocalContext env;
1336 5 : v8::Isolate* isolate = env->GetIsolate();
1337 10 : v8::HandleScope scope(isolate);
1338 5 : v8::Local<v8::Context> context = env.context();
1339 5 : env.ExposeDebug();
1340 :
1341 5 : SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
1342 :
1343 : v8::Local<v8::String> script = v8_str(isolate,
1344 : "function f() {\n"
1345 : " function h() {\n"
1346 : " a = 0; // line 2\n"
1347 : " }\n"
1348 : " b = 1; // line 4\n"
1349 : " return h();\n"
1350 : "}\n"
1351 : "\n"
1352 : "function g() {\n"
1353 : " function h() {\n"
1354 : " a = 0;\n"
1355 : " }\n"
1356 : " b = 2; // line 12\n"
1357 : " h();\n"
1358 : " b = 3; // line 14\n"
1359 : " f(); // line 15\n"
1360 5 : "}");
1361 :
1362 : // Compile the script and get the two functions.
1363 5 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(isolate, "test"));
1364 : v8::Script::Compile(context, script, &origin)
1365 5 : .ToLocalChecked()
1366 : ->Run(context)
1367 5 : .ToLocalChecked();
1368 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
1369 20 : env->Global()->Get(context, v8_str(isolate, "f")).ToLocalChecked());
1370 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
1371 20 : env->Global()->Get(context, v8_str(isolate, "g")).ToLocalChecked());
1372 :
1373 : // Call f and g without break points.
1374 5 : break_point_hit_count = 0;
1375 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1376 5 : CHECK_EQ(0, break_point_hit_count);
1377 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1378 5 : CHECK_EQ(0, break_point_hit_count);
1379 :
1380 : // Call f and g with break point on line 12.
1381 5 : int sbp1 = SetScriptBreakPointByNameFromJS(isolate, "test", 12, 0);
1382 5 : break_point_hit_count = 0;
1383 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1384 5 : CHECK_EQ(0, break_point_hit_count);
1385 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1386 5 : CHECK_EQ(1, break_point_hit_count);
1387 :
1388 : // Remove the break point again.
1389 5 : break_point_hit_count = 0;
1390 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp1);
1391 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1392 5 : CHECK_EQ(0, break_point_hit_count);
1393 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1394 5 : CHECK_EQ(0, break_point_hit_count);
1395 :
1396 : // Call f and g with break point on line 2.
1397 5 : int sbp2 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 2, 0);
1398 5 : break_point_hit_count = 0;
1399 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1400 5 : CHECK_EQ(1, break_point_hit_count);
1401 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1402 5 : CHECK_EQ(2, break_point_hit_count);
1403 :
1404 : // Call f and g with break point on line 2, 4, 12, 14 and 15.
1405 5 : int sbp3 = SetScriptBreakPointByNameFromJS(isolate, "test", 4, 0);
1406 5 : int sbp4 = SetScriptBreakPointByNameFromJS(isolate, "test", 12, 0);
1407 5 : int sbp5 = SetScriptBreakPointByNameFromJS(isolate, "test", 14, 0);
1408 5 : int sbp6 = SetScriptBreakPointByNameFromJS(isolate, "test", 15, 0);
1409 5 : break_point_hit_count = 0;
1410 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1411 5 : CHECK_EQ(2, break_point_hit_count);
1412 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1413 5 : CHECK_EQ(7, break_point_hit_count);
1414 :
1415 : // Remove all the break points again.
1416 5 : break_point_hit_count = 0;
1417 5 : ClearBreakPointFromJS(isolate, sbp2);
1418 5 : ClearBreakPointFromJS(isolate, sbp3);
1419 5 : ClearBreakPointFromJS(isolate, sbp4);
1420 5 : ClearBreakPointFromJS(isolate, sbp5);
1421 5 : ClearBreakPointFromJS(isolate, sbp6);
1422 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1423 5 : CHECK_EQ(0, break_point_hit_count);
1424 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1425 5 : CHECK_EQ(0, break_point_hit_count);
1426 :
1427 5 : SetDebugEventListener(isolate, nullptr);
1428 : CheckDebuggerUnloaded();
1429 :
1430 : // Make sure that the break point numbers are consecutive.
1431 5 : CHECK_EQ(1, sbp1);
1432 5 : CHECK_EQ(2, sbp2);
1433 5 : CHECK_EQ(3, sbp3);
1434 5 : CHECK_EQ(4, sbp4);
1435 5 : CHECK_EQ(5, sbp5);
1436 5 : CHECK_EQ(6, sbp6);
1437 5 : }
1438 :
1439 :
1440 23723 : TEST(ScriptBreakPointByIdThroughJavaScript) {
1441 5 : break_point_hit_count = 0;
1442 5 : DebugLocalContext env;
1443 5 : v8::Isolate* isolate = env->GetIsolate();
1444 10 : v8::HandleScope scope(isolate);
1445 5 : v8::Local<v8::Context> context = env.context();
1446 5 : env.ExposeDebug();
1447 :
1448 5 : SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
1449 :
1450 : v8::Local<v8::String> source = v8_str(isolate,
1451 : "function f() {\n"
1452 : " function h() {\n"
1453 : " a = 0; // line 2\n"
1454 : " }\n"
1455 : " b = 1; // line 4\n"
1456 : " return h();\n"
1457 : "}\n"
1458 : "\n"
1459 : "function g() {\n"
1460 : " function h() {\n"
1461 : " a = 0;\n"
1462 : " }\n"
1463 : " b = 2; // line 12\n"
1464 : " h();\n"
1465 : " b = 3; // line 14\n"
1466 : " f(); // line 15\n"
1467 5 : "}");
1468 :
1469 : // Compile the script and get the two functions.
1470 5 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(isolate, "test"));
1471 : v8::Local<v8::Script> script =
1472 5 : v8::Script::Compile(context, source, &origin).ToLocalChecked();
1473 5 : script->Run(context).ToLocalChecked();
1474 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
1475 20 : env->Global()->Get(context, v8_str(isolate, "f")).ToLocalChecked());
1476 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
1477 20 : env->Global()->Get(context, v8_str(isolate, "g")).ToLocalChecked());
1478 :
1479 : // Get the script id knowing that internally it is a 32 integer.
1480 10 : int script_id = script->GetUnboundScript()->GetId();
1481 :
1482 : // Call f and g without break points.
1483 5 : break_point_hit_count = 0;
1484 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1485 5 : CHECK_EQ(0, break_point_hit_count);
1486 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1487 5 : CHECK_EQ(0, break_point_hit_count);
1488 :
1489 : // Call f and g with break point on line 12.
1490 5 : int sbp1 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 12, 0);
1491 5 : break_point_hit_count = 0;
1492 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1493 5 : CHECK_EQ(0, break_point_hit_count);
1494 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1495 5 : CHECK_EQ(1, break_point_hit_count);
1496 :
1497 : // Remove the break point again.
1498 5 : break_point_hit_count = 0;
1499 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp1);
1500 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1501 5 : CHECK_EQ(0, break_point_hit_count);
1502 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1503 5 : CHECK_EQ(0, break_point_hit_count);
1504 :
1505 : // Call f and g with break point on line 2.
1506 5 : int sbp2 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 2, 0);
1507 5 : break_point_hit_count = 0;
1508 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1509 5 : CHECK_EQ(1, break_point_hit_count);
1510 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1511 5 : CHECK_EQ(2, break_point_hit_count);
1512 :
1513 : // Call f and g with break point on line 2, 4, 12, 14 and 15.
1514 5 : int sbp3 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 4, 0);
1515 5 : int sbp4 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 12, 0);
1516 5 : int sbp5 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 14, 0);
1517 5 : int sbp6 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 15, 0);
1518 5 : break_point_hit_count = 0;
1519 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1520 5 : CHECK_EQ(2, break_point_hit_count);
1521 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1522 5 : CHECK_EQ(7, break_point_hit_count);
1523 :
1524 : // Remove all the break points again.
1525 5 : break_point_hit_count = 0;
1526 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp2);
1527 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp3);
1528 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp4);
1529 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp5);
1530 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp6);
1531 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1532 5 : CHECK_EQ(0, break_point_hit_count);
1533 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1534 5 : CHECK_EQ(0, break_point_hit_count);
1535 :
1536 5 : SetDebugEventListener(isolate, nullptr);
1537 : CheckDebuggerUnloaded();
1538 :
1539 : // Make sure that the break point numbers are consecutive.
1540 5 : CHECK_EQ(1, sbp1);
1541 5 : CHECK_EQ(2, sbp2);
1542 5 : CHECK_EQ(3, sbp3);
1543 5 : CHECK_EQ(4, sbp4);
1544 5 : CHECK_EQ(5, sbp5);
1545 5 : CHECK_EQ(6, sbp6);
1546 5 : }
1547 :
1548 :
1549 : // Test conditional script break points.
1550 23723 : TEST(EnableDisableScriptBreakPoint) {
1551 5 : break_point_hit_count = 0;
1552 5 : DebugLocalContext env;
1553 5 : v8::Isolate* isolate = env->GetIsolate();
1554 10 : v8::HandleScope scope(isolate);
1555 5 : v8::Local<v8::Context> context = env.context();
1556 5 : env.ExposeDebug();
1557 :
1558 5 : SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
1559 :
1560 : v8::Local<v8::String> script = v8_str(isolate,
1561 : "function f() {\n"
1562 : " a = 0; // line 1\n"
1563 5 : "};");
1564 :
1565 : // Compile the script and get function f.
1566 5 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(isolate, "test"));
1567 : v8::Script::Compile(context, script, &origin)
1568 5 : .ToLocalChecked()
1569 : ->Run(context)
1570 5 : .ToLocalChecked();
1571 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
1572 20 : env->Global()->Get(context, v8_str(isolate, "f")).ToLocalChecked());
1573 :
1574 : // Set script break point on line 1 (in function f).
1575 5 : int sbp = SetScriptBreakPointByNameFromJS(isolate, "test", 1, 0);
1576 :
1577 : // Call f while enabeling and disabling the script break point.
1578 5 : break_point_hit_count = 0;
1579 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1580 5 : CHECK_EQ(1, break_point_hit_count);
1581 :
1582 5 : DisableScriptBreakPointFromJS(isolate, sbp);
1583 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1584 5 : CHECK_EQ(1, break_point_hit_count);
1585 :
1586 5 : EnableScriptBreakPointFromJS(isolate, sbp);
1587 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1588 5 : CHECK_EQ(2, break_point_hit_count);
1589 :
1590 5 : DisableScriptBreakPointFromJS(isolate, sbp);
1591 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1592 5 : CHECK_EQ(2, break_point_hit_count);
1593 :
1594 5 : SetDebugEventListener(isolate, nullptr);
1595 : CheckDebuggerUnloaded();
1596 5 : }
1597 :
1598 :
1599 : // Test conditional script break points.
1600 23723 : TEST(ConditionalScriptBreakPoint) {
1601 5 : break_point_hit_count = 0;
1602 5 : DebugLocalContext env;
1603 10 : v8::HandleScope scope(env->GetIsolate());
1604 5 : env.ExposeDebug();
1605 :
1606 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
1607 :
1608 : v8::Local<v8::String> script = v8_str(env->GetIsolate(),
1609 : "count = 0;\n"
1610 : "function f() {\n"
1611 : " g(count++); // line 2\n"
1612 : "};\n"
1613 : "function g(x) {\n"
1614 : " var a=x; // line 5\n"
1615 5 : "};");
1616 :
1617 : // Compile the script and get function f.
1618 5 : v8::Local<v8::Context> context = env.context();
1619 5 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(env->GetIsolate(), "test"));
1620 : v8::Script::Compile(context, script, &origin)
1621 5 : .ToLocalChecked()
1622 : ->Run(context)
1623 5 : .ToLocalChecked();
1624 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
1625 : env->Global()
1626 15 : ->Get(context, v8_str(env->GetIsolate(), "f"))
1627 5 : .ToLocalChecked());
1628 :
1629 : // Set script break point on line 5 (in function g).
1630 5 : int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 5, 0);
1631 :
1632 : // Call f with different conditions on the script break point.
1633 5 : break_point_hit_count = 0;
1634 5 : ChangeScriptBreakPointConditionFromJS(env->GetIsolate(), sbp1, "false");
1635 15 : f->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
1636 5 : CHECK_EQ(0, break_point_hit_count);
1637 :
1638 5 : ChangeScriptBreakPointConditionFromJS(env->GetIsolate(), sbp1, "true");
1639 5 : break_point_hit_count = 0;
1640 15 : f->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
1641 5 : CHECK_EQ(1, break_point_hit_count);
1642 :
1643 5 : ChangeScriptBreakPointConditionFromJS(env->GetIsolate(), sbp1, "x % 2 == 0");
1644 5 : break_point_hit_count = 0;
1645 55 : for (int i = 0; i < 10; i++) {
1646 150 : f->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
1647 : }
1648 5 : CHECK_EQ(5, break_point_hit_count);
1649 :
1650 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
1651 : CheckDebuggerUnloaded();
1652 5 : }
1653 :
1654 :
1655 : // Test when several scripts has the same script data
1656 23723 : TEST(ScriptBreakPointMultiple) {
1657 5 : break_point_hit_count = 0;
1658 5 : DebugLocalContext env;
1659 10 : v8::HandleScope scope(env->GetIsolate());
1660 5 : env.ExposeDebug();
1661 :
1662 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
1663 :
1664 5 : v8::Local<v8::Context> context = env.context();
1665 : v8::Local<v8::Function> f;
1666 : v8::Local<v8::String> script_f = v8_str(env->GetIsolate(),
1667 : "function f() {\n"
1668 : " a = 0; // line 1\n"
1669 5 : "}");
1670 :
1671 : v8::Local<v8::Function> g;
1672 : v8::Local<v8::String> script_g = v8_str(env->GetIsolate(),
1673 : "function g() {\n"
1674 : " b = 0; // line 1\n"
1675 5 : "}");
1676 :
1677 5 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(env->GetIsolate(), "test"));
1678 :
1679 : // Compile the scripts with same script data and get the functions.
1680 : v8::Script::Compile(context, script_f, &origin)
1681 5 : .ToLocalChecked()
1682 : ->Run(context)
1683 5 : .ToLocalChecked();
1684 : f = v8::Local<v8::Function>::Cast(
1685 : env->Global()
1686 15 : ->Get(context, v8_str(env->GetIsolate(), "f"))
1687 5 : .ToLocalChecked());
1688 : v8::Script::Compile(context, script_g, &origin)
1689 5 : .ToLocalChecked()
1690 : ->Run(context)
1691 5 : .ToLocalChecked();
1692 : g = v8::Local<v8::Function>::Cast(
1693 : env->Global()
1694 15 : ->Get(context, v8_str(env->GetIsolate(), "g"))
1695 5 : .ToLocalChecked());
1696 :
1697 5 : int sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0);
1698 :
1699 : // Call f and g and check that the script break point is active.
1700 5 : break_point_hit_count = 0;
1701 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1702 5 : CHECK_EQ(1, break_point_hit_count);
1703 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1704 5 : CHECK_EQ(2, break_point_hit_count);
1705 :
1706 : // Clear the script break point.
1707 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp);
1708 :
1709 : // Call f and g and check that the script break point is no longer active.
1710 5 : break_point_hit_count = 0;
1711 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1712 5 : CHECK_EQ(0, break_point_hit_count);
1713 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1714 5 : CHECK_EQ(0, break_point_hit_count);
1715 :
1716 : // Set script break point with the scripts loaded.
1717 5 : sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0);
1718 :
1719 : // Call f and g and check that the script break point is active.
1720 5 : break_point_hit_count = 0;
1721 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1722 5 : CHECK_EQ(1, break_point_hit_count);
1723 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1724 5 : CHECK_EQ(2, break_point_hit_count);
1725 :
1726 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
1727 : CheckDebuggerUnloaded();
1728 5 : }
1729 :
1730 :
1731 : // Test the script origin which has both name and line offset.
1732 23723 : TEST(ScriptBreakPointLineOffset) {
1733 5 : break_point_hit_count = 0;
1734 5 : DebugLocalContext env;
1735 10 : v8::HandleScope scope(env->GetIsolate());
1736 5 : env.ExposeDebug();
1737 :
1738 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
1739 :
1740 5 : v8::Local<v8::Context> context = env.context();
1741 : v8::Local<v8::Function> f;
1742 : v8::Local<v8::String> script =
1743 : v8_str(env->GetIsolate(),
1744 : "function f() {\n"
1745 : " a = 0; // line 8 as this script has line offset 7\n"
1746 : " b = 0; // line 9 as this script has line offset 7\n"
1747 5 : "}");
1748 :
1749 : // Create script origin both name and line offset.
1750 : v8::ScriptOrigin origin(v8_str(env->GetIsolate(), "test.html"),
1751 10 : v8::Integer::New(env->GetIsolate(), 7));
1752 :
1753 : // Compile the script and get the function.
1754 : v8::Script::Compile(context, script, &origin)
1755 5 : .ToLocalChecked()
1756 : ->Run(context)
1757 5 : .ToLocalChecked();
1758 :
1759 : int sbp1 =
1760 5 : SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 8, 0);
1761 : int sbp2 =
1762 5 : SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 9, 0);
1763 :
1764 : f = v8::Local<v8::Function>::Cast(
1765 : env->Global()
1766 15 : ->Get(context, v8_str(env->GetIsolate(), "f"))
1767 5 : .ToLocalChecked());
1768 :
1769 : // Call f and check that the script break point is active.
1770 5 : break_point_hit_count = 0;
1771 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1772 5 : CHECK_EQ(2, break_point_hit_count);
1773 :
1774 : // Clear the script break points.
1775 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp1);
1776 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp2);
1777 :
1778 : // Call f and check that no script break points are active.
1779 5 : break_point_hit_count = 0;
1780 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1781 5 : CHECK_EQ(0, break_point_hit_count);
1782 :
1783 : // Set a script break point with the script loaded.
1784 5 : sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 9, 0);
1785 :
1786 : // Call f and check that the script break point is active.
1787 5 : break_point_hit_count = 0;
1788 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1789 5 : CHECK_EQ(1, break_point_hit_count);
1790 :
1791 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
1792 : CheckDebuggerUnloaded();
1793 5 : }
1794 :
1795 :
1796 : // Test script break points set on lines.
1797 23723 : TEST(ScriptBreakPointLine) {
1798 5 : DebugLocalContext env;
1799 10 : v8::HandleScope scope(env->GetIsolate());
1800 5 : env.ExposeDebug();
1801 :
1802 : // Create a function for checking the function when hitting a break point.
1803 : frame_function_name = CompileFunction(&env,
1804 : frame_function_name_source,
1805 5 : "frame_function_name");
1806 :
1807 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
1808 :
1809 5 : v8::Local<v8::Context> context = env.context();
1810 : v8::Local<v8::Function> f;
1811 : v8::Local<v8::Function> g;
1812 : v8::Local<v8::String> script =
1813 : v8_str(env->GetIsolate(),
1814 : "a = 0 // line 0\n"
1815 : "function f() {\n"
1816 : " a = 1; // line 2\n"
1817 : "}\n"
1818 : " a = 2; // line 4\n"
1819 : " /* xx */ function g() { // line 5\n"
1820 : " function h() { // line 6\n"
1821 : " a = 3; // line 7\n"
1822 : " }\n"
1823 : " h(); // line 9\n"
1824 : " a = 4; // line 10\n"
1825 : " }\n"
1826 5 : " a=5; // line 12");
1827 :
1828 : // Compile the script and get the function.
1829 5 : break_point_hit_count = 0;
1830 : v8::ScriptOrigin origin(v8_str(env->GetIsolate(), "test.html"),
1831 10 : v8::Integer::New(env->GetIsolate(), 0));
1832 : v8::Local<v8::Script> compiled =
1833 5 : v8::Script::Compile(context, script, &origin).ToLocalChecked();
1834 :
1835 : int sbp1 =
1836 5 : SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 0, -1);
1837 : int sbp2 =
1838 5 : SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 1, -1);
1839 : int sbp3 =
1840 5 : SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 5, -1);
1841 :
1842 5 : compiled->Run(context).ToLocalChecked();
1843 :
1844 : f = v8::Local<v8::Function>::Cast(
1845 : env->Global()
1846 15 : ->Get(context, v8_str(env->GetIsolate(), "f"))
1847 5 : .ToLocalChecked());
1848 : g = v8::Local<v8::Function>::Cast(
1849 : env->Global()
1850 15 : ->Get(context, v8_str(env->GetIsolate(), "g"))
1851 5 : .ToLocalChecked());
1852 :
1853 : // Check that a break point was hit when the script was run.
1854 5 : CHECK_EQ(1, break_point_hit_count);
1855 5 : CHECK_EQ(0, StrLength(last_function_hit));
1856 :
1857 : // Call f and check that the script break point.
1858 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1859 5 : CHECK_EQ(2, break_point_hit_count);
1860 5 : CHECK_EQ(0, strcmp("f", last_function_hit));
1861 :
1862 : // Call g and check that the script break point.
1863 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1864 5 : CHECK_EQ(3, break_point_hit_count);
1865 5 : CHECK_EQ(0, strcmp("g", last_function_hit));
1866 :
1867 : // Clear the script break point on g and set one on h.
1868 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp3);
1869 : int sbp4 =
1870 5 : SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 6, -1);
1871 :
1872 : // Call g and check that the script break point in h is hit.
1873 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1874 5 : CHECK_EQ(4, break_point_hit_count);
1875 5 : CHECK_EQ(0, strcmp("h", last_function_hit));
1876 :
1877 : // Clear break points in f and h. Set a new one in the script between
1878 : // functions f and g and test that there is no break points in f and g any
1879 : // more.
1880 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp2);
1881 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp4);
1882 : int sbp5 =
1883 5 : SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 4, -1);
1884 5 : break_point_hit_count = 0;
1885 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1886 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1887 5 : CHECK_EQ(0, break_point_hit_count);
1888 :
1889 : // Set a break point in the code after the last function decleration.
1890 : int sbp6 =
1891 5 : SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 12, -1);
1892 :
1893 : // Reloading the script should not hit any break points.
1894 5 : break_point_hit_count = 0;
1895 : v8::Script::Compile(context, script, &origin)
1896 5 : .ToLocalChecked()
1897 : ->Run(context)
1898 5 : .ToLocalChecked();
1899 5 : CHECK_EQ(0, break_point_hit_count);
1900 :
1901 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp1);
1902 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp5);
1903 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp6);
1904 :
1905 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
1906 : CheckDebuggerUnloaded();
1907 5 : }
1908 :
1909 :
1910 : // Test top level script break points set on lines.
1911 23723 : TEST(ScriptBreakPointLineTopLevel) {
1912 5 : DebugLocalContext env;
1913 10 : v8::HandleScope scope(env->GetIsolate());
1914 5 : env.ExposeDebug();
1915 :
1916 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
1917 :
1918 5 : v8::Local<v8::Context> context = env.context();
1919 : v8::Local<v8::String> script =
1920 : v8_str(env->GetIsolate(),
1921 : "function f() {\n"
1922 : " a = 1; // line 1\n"
1923 : "}\n"
1924 5 : "a = 2; // line 3\n");
1925 : v8::Local<v8::Function> f;
1926 : {
1927 5 : v8::HandleScope scope(env->GetIsolate());
1928 5 : CompileRunWithOrigin(script, "test.html");
1929 : }
1930 : f = v8::Local<v8::Function>::Cast(
1931 : env->Global()
1932 15 : ->Get(context, v8_str(env->GetIsolate(), "f"))
1933 5 : .ToLocalChecked());
1934 :
1935 5 : CcTest::CollectAllGarbage();
1936 :
1937 5 : SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 3, -1);
1938 :
1939 : // Call f and check that there was no break points.
1940 5 : break_point_hit_count = 0;
1941 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
1942 5 : CHECK_EQ(0, break_point_hit_count);
1943 :
1944 : // Recompile and run script and check that break point was not reapplied.
1945 5 : break_point_hit_count = 0;
1946 5 : CompileRunWithOrigin(script, "test.html");
1947 5 : CHECK_EQ(0, break_point_hit_count);
1948 :
1949 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
1950 : CheckDebuggerUnloaded();
1951 5 : }
1952 :
1953 :
1954 : // Test that it is possible to add and remove break points in a top level
1955 : // function which has no references but has not been collected yet.
1956 23723 : TEST(ScriptBreakPointTopLevelCrash) {
1957 5 : DebugLocalContext env;
1958 10 : v8::HandleScope scope(env->GetIsolate());
1959 5 : env.ExposeDebug();
1960 :
1961 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
1962 :
1963 : CompileRunWithOrigin(
1964 : "function f() {\n"
1965 : " return 0;\n"
1966 : "}\n",
1967 : "test.html");
1968 : int sbp1 =
1969 5 : SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 1, -1);
1970 5 : break_point_hit_count = 0;
1971 :
1972 : CompileRun("f();");
1973 :
1974 5 : CHECK_EQ(1, break_point_hit_count);
1975 :
1976 : int sbp2 =
1977 5 : SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 3, -1);
1978 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp1);
1979 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp2);
1980 :
1981 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
1982 : CheckDebuggerUnloaded();
1983 5 : }
1984 :
1985 :
1986 : // Test that it is possible to remove the last break point for a function
1987 : // inside the break handling of that break point.
1988 23723 : TEST(RemoveBreakPointInBreak) {
1989 5 : DebugLocalContext env;
1990 10 : v8::HandleScope scope(env->GetIsolate());
1991 :
1992 5 : v8::Local<v8::Context> context = env.context();
1993 : v8::Local<v8::Function> foo =
1994 5 : CompileFunction(&env, "function foo(){a=1;}", "foo");
1995 :
1996 : // Register the debug event listener pasing the function
1997 5 : SetDebugEventListener(env->GetIsolate(), DebugEventRemoveBreakPoint, foo);
1998 :
1999 5 : debug_event_remove_break_point = SetBreakPoint(foo, 0);
2000 :
2001 5 : break_point_hit_count = 0;
2002 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2003 5 : CHECK_EQ(1, break_point_hit_count);
2004 :
2005 5 : break_point_hit_count = 0;
2006 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2007 5 : CHECK_EQ(0, break_point_hit_count);
2008 :
2009 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
2010 : CheckDebuggerUnloaded();
2011 5 : }
2012 :
2013 :
2014 : // Test that the debugger statement causes a break.
2015 23723 : TEST(DebuggerStatement) {
2016 5 : break_point_hit_count = 0;
2017 5 : DebugLocalContext env;
2018 10 : v8::HandleScope scope(env->GetIsolate());
2019 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
2020 5 : v8::Local<v8::Context> context = env.context();
2021 : v8::Script::Compile(context,
2022 5 : v8_str(env->GetIsolate(), "function bar(){debugger}"))
2023 5 : .ToLocalChecked()
2024 : ->Run(context)
2025 5 : .ToLocalChecked();
2026 : v8::Script::Compile(
2027 5 : context, v8_str(env->GetIsolate(), "function foo(){debugger;debugger;}"))
2028 5 : .ToLocalChecked()
2029 : ->Run(context)
2030 5 : .ToLocalChecked();
2031 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
2032 : env->Global()
2033 15 : ->Get(context, v8_str(env->GetIsolate(), "foo"))
2034 5 : .ToLocalChecked());
2035 : v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
2036 : env->Global()
2037 15 : ->Get(context, v8_str(env->GetIsolate(), "bar"))
2038 5 : .ToLocalChecked());
2039 :
2040 : // Run function with debugger statement
2041 15 : bar->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2042 5 : CHECK_EQ(1, break_point_hit_count);
2043 :
2044 : // Run function with two debugger statement
2045 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2046 5 : CHECK_EQ(3, break_point_hit_count);
2047 :
2048 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
2049 : CheckDebuggerUnloaded();
2050 5 : }
2051 :
2052 :
2053 : // Test setting a breakpoint on the debugger statement.
2054 23723 : TEST(DebuggerStatementBreakpoint) {
2055 5 : break_point_hit_count = 0;
2056 5 : DebugLocalContext env;
2057 10 : v8::HandleScope scope(env->GetIsolate());
2058 5 : v8::Local<v8::Context> context = env.context();
2059 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
2060 : v8::Script::Compile(context,
2061 5 : v8_str(env->GetIsolate(), "function foo(){debugger;}"))
2062 5 : .ToLocalChecked()
2063 : ->Run(context)
2064 5 : .ToLocalChecked();
2065 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
2066 : env->Global()
2067 15 : ->Get(context, v8_str(env->GetIsolate(), "foo"))
2068 5 : .ToLocalChecked());
2069 :
2070 : // The debugger statement triggers breakpoint hit
2071 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2072 5 : CHECK_EQ(1, break_point_hit_count);
2073 :
2074 5 : int bp = SetBreakPoint(foo, 0);
2075 :
2076 : // Set breakpoint does not duplicate hits
2077 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2078 5 : CHECK_EQ(2, break_point_hit_count);
2079 :
2080 5 : ClearBreakPoint(bp);
2081 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
2082 : CheckDebuggerUnloaded();
2083 5 : }
2084 :
2085 :
2086 : // Test that the evaluation of expressions when a break point is hit generates
2087 : // the correct results.
2088 23723 : TEST(DebugEvaluate) {
2089 5 : DebugLocalContext env;
2090 5 : v8::Isolate* isolate = env->GetIsolate();
2091 10 : v8::HandleScope scope(isolate);
2092 5 : env.ExposeDebug();
2093 :
2094 : // Create a function for checking the evaluation when hitting a break point.
2095 : evaluate_check_function = CompileFunction(&env,
2096 : evaluate_check_source,
2097 5 : "evaluate_check");
2098 : // Register the debug event listener
2099 5 : SetDebugEventListener(isolate, DebugEventEvaluate);
2100 :
2101 : // Different expected vaules of x and a when in a break point (u = undefined,
2102 : // d = Hello, world!).
2103 : struct EvaluateCheck checks_uu[] = {{"x", v8::Undefined(isolate)},
2104 : {"a", v8::Undefined(isolate)},
2105 15 : {nullptr, v8::Local<v8::Value>()}};
2106 : struct EvaluateCheck checks_hu[] = {
2107 : {"x", v8_str(env->GetIsolate(), "Hello, world!")},
2108 : {"a", v8::Undefined(isolate)},
2109 20 : {nullptr, v8::Local<v8::Value>()}};
2110 : struct EvaluateCheck checks_hh[] = {
2111 : {"x", v8_str(env->GetIsolate(), "Hello, world!")},
2112 : {"a", v8_str(env->GetIsolate(), "Hello, world!")},
2113 25 : {nullptr, v8::Local<v8::Value>()}};
2114 :
2115 : // Simple test function. The "y=0" is in the function foo to provide a break
2116 : // location. For "y=0" the "y" is at position 15 in the foo function
2117 : // therefore setting breakpoint at position 15 will break at "y=0" and
2118 : // setting it higher will break after.
2119 : v8::Local<v8::Function> foo = CompileFunction(&env,
2120 : "function foo(x) {"
2121 : " var a;"
2122 : " y=0;" // To ensure break location 1.
2123 : " a=x;"
2124 : " y=0;" // To ensure break location 2.
2125 : "}",
2126 5 : "foo");
2127 : const int foo_break_position_1 = 15;
2128 : const int foo_break_position_2 = 29;
2129 :
2130 5 : v8::Local<v8::Context> context = env.context();
2131 : // Arguments with one parameter "Hello, world!"
2132 : v8::Local<v8::Value> argv_foo[1] = {
2133 5 : v8_str(env->GetIsolate(), "Hello, world!")};
2134 :
2135 : // Call foo with breakpoint set before a=x and undefined as parameter.
2136 5 : int bp = SetBreakPoint(foo, foo_break_position_1);
2137 5 : checks = checks_uu;
2138 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2139 :
2140 : // Call foo with breakpoint set before a=x and parameter "Hello, world!".
2141 5 : checks = checks_hu;
2142 15 : foo->Call(context, env->Global(), 1, argv_foo).ToLocalChecked();
2143 :
2144 : // Call foo with breakpoint set after a=x and parameter "Hello, world!".
2145 5 : ClearBreakPoint(bp);
2146 5 : SetBreakPoint(foo, foo_break_position_2);
2147 5 : checks = checks_hh;
2148 15 : foo->Call(context, env->Global(), 1, argv_foo).ToLocalChecked();
2149 :
2150 : // Test that overriding Object.prototype will not interfere into evaluation
2151 : // on call frame.
2152 : v8::Local<v8::Function> zoo =
2153 : CompileFunction(&env,
2154 : "x = undefined;"
2155 : "function zoo(t) {"
2156 : " var a=x;"
2157 : " Object.prototype.x = 42;"
2158 : " x=t;"
2159 : " y=0;" // To ensure break location.
2160 : " delete Object.prototype.x;"
2161 : " x=a;"
2162 : "}",
2163 5 : "zoo");
2164 : const int zoo_break_position = 50;
2165 :
2166 : // Arguments with one parameter "Hello, world!"
2167 : v8::Local<v8::Value> argv_zoo[1] = {
2168 5 : v8_str(env->GetIsolate(), "Hello, world!")};
2169 :
2170 : // Call zoo with breakpoint set at y=0.
2171 : DebugEventCounterClear();
2172 5 : bp = SetBreakPoint(zoo, zoo_break_position);
2173 5 : checks = checks_hu;
2174 15 : zoo->Call(context, env->Global(), 1, argv_zoo).ToLocalChecked();
2175 5 : CHECK_EQ(1, break_point_hit_count);
2176 5 : ClearBreakPoint(bp);
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 5 : "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 5 : checks = checks_uu;
2201 : v8::Local<v8::Value> argv_bar_1[2] = {
2202 5 : v8::Undefined(isolate), v8::Number::New(isolate, barbar_break_position)};
2203 15 : bar->Call(context, env->Global(), 2, argv_bar_1).ToLocalChecked();
2204 :
2205 : // Call bar setting breakpoint before a=x in barbar and parameter
2206 : // "Hello, world!".
2207 5 : checks = checks_hu;
2208 : v8::Local<v8::Value> argv_bar_2[2] = {
2209 : v8_str(env->GetIsolate(), "Hello, world!"),
2210 10 : v8::Number::New(env->GetIsolate(), barbar_break_position)};
2211 15 : bar->Call(context, env->Global(), 2, argv_bar_2).ToLocalChecked();
2212 :
2213 : // Call bar setting breakpoint after a=x in barbar and parameter
2214 : // "Hello, world!".
2215 5 : checks = checks_hh;
2216 : v8::Local<v8::Value> argv_bar_3[2] = {
2217 : v8_str(env->GetIsolate(), "Hello, world!"),
2218 10 : v8::Number::New(env->GetIsolate(), barbar_break_position + 1)};
2219 15 : bar->Call(context, env->Global(), 2, argv_bar_3).ToLocalChecked();
2220 :
2221 5 : SetDebugEventListener(isolate, nullptr);
2222 : CheckDebuggerUnloaded();
2223 5 : }
2224 :
2225 :
2226 : int debugEventCount = 0;
2227 20 : static void CheckDebugEvent(const v8::Debug::EventDetails& eventDetails) {
2228 20 : if (eventDetails.GetEvent() == v8::Break) ++debugEventCount;
2229 20 : }
2230 :
2231 :
2232 : // Test that the conditional breakpoints work event if code generation from
2233 : // strings is prohibited in the debugee context.
2234 23723 : TEST(ConditionalBreakpointWithCodeGenerationDisallowed) {
2235 5 : DebugLocalContext env;
2236 10 : v8::HandleScope scope(env->GetIsolate());
2237 5 : env.ExposeDebug();
2238 :
2239 5 : SetDebugEventListener(env->GetIsolate(), CheckDebugEvent);
2240 :
2241 5 : v8::Local<v8::Context> context = env.context();
2242 : v8::Local<v8::Function> foo = CompileFunction(&env,
2243 : "function foo(x) {\n"
2244 : " var s = 'String value2';\n"
2245 : " return s + x;\n"
2246 : "}",
2247 5 : "foo");
2248 :
2249 : // Set conditional breakpoint with condition 'true'.
2250 : CompileRun("debug.Debug.setBreakPoint(foo, 2, 0, 'true')");
2251 :
2252 5 : debugEventCount = 0;
2253 5 : env->AllowCodeGenerationFromStrings(false);
2254 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2255 5 : CHECK_EQ(1, debugEventCount);
2256 :
2257 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
2258 : CheckDebuggerUnloaded();
2259 5 : }
2260 :
2261 :
2262 : bool checkedDebugEvals = true;
2263 : v8::Local<v8::Function> checkGlobalEvalFunction;
2264 : v8::Local<v8::Function> checkFrameEvalFunction;
2265 30 : static void CheckDebugEval(const v8::Debug::EventDetails& eventDetails) {
2266 30 : if (eventDetails.GetEvent() == v8::Break) {
2267 5 : ++debugEventCount;
2268 5 : v8::HandleScope handleScope(CcTest::isolate());
2269 :
2270 5 : v8::Local<v8::Value> args[] = {eventDetails.GetExecutionState()};
2271 25 : CHECK(
2272 : checkGlobalEvalFunction->Call(eventDetails.GetEventContext(),
2273 : eventDetails.GetEventContext()->Global(),
2274 : 1, args)
2275 : .ToLocalChecked()
2276 : ->IsTrue());
2277 25 : CHECK(checkFrameEvalFunction->Call(eventDetails.GetEventContext(),
2278 : eventDetails.GetEventContext()->Global(),
2279 : 1, args)
2280 : .ToLocalChecked()
2281 5 : ->IsTrue());
2282 : }
2283 30 : }
2284 :
2285 :
2286 : // Test that the evaluation of expressions when a break point is hit generates
2287 : // the correct results in case code generation from strings is disallowed in the
2288 : // debugee context.
2289 23723 : TEST(DebugEvaluateWithCodeGenerationDisallowed) {
2290 5 : DebugLocalContext env;
2291 10 : v8::HandleScope scope(env->GetIsolate());
2292 5 : env.ExposeDebug();
2293 :
2294 5 : SetDebugEventListener(env->GetIsolate(), CheckDebugEval);
2295 :
2296 5 : v8::Local<v8::Context> context = env.context();
2297 : v8::Local<v8::Function> foo = CompileFunction(&env,
2298 : "var global = 'Global';\n"
2299 : "function foo(x) {\n"
2300 : " var local = 'Local';\n"
2301 : " debugger;\n"
2302 : " return local + x;\n"
2303 : "}",
2304 5 : "foo");
2305 : checkGlobalEvalFunction = CompileFunction(&env,
2306 : "function checkGlobalEval(exec_state) {\n"
2307 : " return exec_state.evaluateGlobal('global').value() === 'Global';\n"
2308 : "}",
2309 5 : "checkGlobalEval");
2310 :
2311 : checkFrameEvalFunction = CompileFunction(&env,
2312 : "function checkFrameEval(exec_state) {\n"
2313 : " return exec_state.frame(0).evaluate('local').value() === 'Local';\n"
2314 : "}",
2315 5 : "checkFrameEval");
2316 5 : debugEventCount = 0;
2317 5 : env->AllowCodeGenerationFromStrings(false);
2318 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2319 5 : CHECK_EQ(1, debugEventCount);
2320 :
2321 : checkGlobalEvalFunction.Clear();
2322 : checkFrameEvalFunction.Clear();
2323 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
2324 : CheckDebuggerUnloaded();
2325 5 : }
2326 :
2327 :
2328 : // Simple test of the stepping mechanism using only store ICs.
2329 23723 : TEST(DebugStepLinear) {
2330 5 : DebugLocalContext env;
2331 10 : v8::HandleScope scope(env->GetIsolate());
2332 :
2333 : // Create a function for testing stepping.
2334 : v8::Local<v8::Function> foo = CompileFunction(&env,
2335 : "function foo(){a=1;b=1;c=1;}",
2336 5 : "foo");
2337 :
2338 : // Run foo to allow it to get optimized.
2339 : CompileRun("a=0; b=0; c=0; foo();");
2340 :
2341 : // Register a debug event listener which steps and counts.
2342 5 : SetDebugEventListener(env->GetIsolate(), DebugEventStep);
2343 :
2344 5 : SetBreakPoint(foo, 3);
2345 :
2346 5 : step_action = StepIn;
2347 5 : break_point_hit_count = 0;
2348 5 : v8::Local<v8::Context> context = env.context();
2349 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2350 :
2351 : // With stepping all break locations are hit.
2352 5 : CHECK_EQ(4, break_point_hit_count);
2353 :
2354 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
2355 : CheckDebuggerUnloaded();
2356 :
2357 : // Register a debug event listener which just counts.
2358 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
2359 :
2360 5 : SetBreakPoint(foo, 3);
2361 5 : break_point_hit_count = 0;
2362 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2363 :
2364 : // Without stepping only active break points are hit.
2365 5 : CHECK_EQ(1, break_point_hit_count);
2366 :
2367 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
2368 : CheckDebuggerUnloaded();
2369 5 : }
2370 :
2371 :
2372 : // Test of the stepping mechanism for keyed load in a loop.
2373 23723 : TEST(DebugStepKeyedLoadLoop) {
2374 5 : DebugLocalContext env;
2375 10 : v8::HandleScope scope(env->GetIsolate());
2376 :
2377 : // Register a debug event listener which steps and counts.
2378 5 : SetDebugEventListener(env->GetIsolate(), DebugEventStep);
2379 :
2380 : // Create a function for testing stepping of keyed load. The statement 'y=1'
2381 : // is there to have more than one breakable statement in the loop, TODO(315).
2382 : v8::Local<v8::Function> foo = CompileFunction(
2383 : &env,
2384 : "function foo(a) {\n"
2385 : " var x;\n"
2386 : " var len = a.length;\n"
2387 : " for (var i = 0; i < len; i++) {\n"
2388 : " y = 1;\n"
2389 : " x = a[i];\n"
2390 : " }\n"
2391 : "}\n"
2392 : "y=0\n",
2393 5 : "foo");
2394 :
2395 5 : v8::Local<v8::Context> context = env.context();
2396 : // Create array [0,1,2,3,4,5,6,7,8,9]
2397 5 : v8::Local<v8::Array> a = v8::Array::New(env->GetIsolate(), 10);
2398 55 : for (int i = 0; i < 10; i++) {
2399 250 : CHECK(a->Set(context, v8::Number::New(env->GetIsolate(), i),
2400 : v8::Number::New(env->GetIsolate(), i))
2401 : .FromJust());
2402 : }
2403 :
2404 : // Call function without any break points to ensure inlining is in place.
2405 : const int kArgc = 1;
2406 : v8::Local<v8::Value> args[kArgc] = {a};
2407 15 : foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
2408 :
2409 : // Set up break point and step through the function.
2410 5 : SetBreakPoint(foo, 3);
2411 5 : step_action = StepNext;
2412 5 : break_point_hit_count = 0;
2413 15 : foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
2414 :
2415 : // With stepping all break locations are hit.
2416 5 : CHECK_EQ(44, break_point_hit_count);
2417 :
2418 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
2419 : CheckDebuggerUnloaded();
2420 5 : }
2421 :
2422 :
2423 : // Test of the stepping mechanism for keyed store in a loop.
2424 23723 : TEST(DebugStepKeyedStoreLoop) {
2425 5 : DebugLocalContext env;
2426 10 : v8::HandleScope scope(env->GetIsolate());
2427 :
2428 : // Register a debug event listener which steps and counts.
2429 5 : SetDebugEventListener(env->GetIsolate(), DebugEventStep);
2430 :
2431 : // Create a function for testing stepping of keyed store. The statement 'y=1'
2432 : // is there to have more than one breakable statement in the loop, TODO(315).
2433 : v8::Local<v8::Function> foo = CompileFunction(
2434 : &env,
2435 : "function foo(a) {\n"
2436 : " var len = a.length;\n"
2437 : " for (var i = 0; i < len; i++) {\n"
2438 : " y = 1;\n"
2439 : " a[i] = 42;\n"
2440 : " }\n"
2441 : "}\n"
2442 : "y=0\n",
2443 5 : "foo");
2444 :
2445 5 : v8::Local<v8::Context> context = env.context();
2446 : // Create array [0,1,2,3,4,5,6,7,8,9]
2447 5 : v8::Local<v8::Array> a = v8::Array::New(env->GetIsolate(), 10);
2448 55 : for (int i = 0; i < 10; i++) {
2449 250 : CHECK(a->Set(context, v8::Number::New(env->GetIsolate(), i),
2450 : v8::Number::New(env->GetIsolate(), i))
2451 : .FromJust());
2452 : }
2453 :
2454 : // Call function without any break points to ensure inlining is in place.
2455 : const int kArgc = 1;
2456 : v8::Local<v8::Value> args[kArgc] = {a};
2457 15 : foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
2458 :
2459 : // Set up break point and step through the function.
2460 5 : SetBreakPoint(foo, 3);
2461 5 : step_action = StepNext;
2462 5 : break_point_hit_count = 0;
2463 15 : foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
2464 :
2465 : // With stepping all break locations are hit.
2466 5 : CHECK_EQ(44, break_point_hit_count);
2467 :
2468 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
2469 : CheckDebuggerUnloaded();
2470 5 : }
2471 :
2472 :
2473 : // Test of the stepping mechanism for named load in a loop.
2474 23723 : TEST(DebugStepNamedLoadLoop) {
2475 5 : DebugLocalContext env;
2476 10 : v8::HandleScope scope(env->GetIsolate());
2477 :
2478 : // Register a debug event listener which steps and counts.
2479 5 : SetDebugEventListener(env->GetIsolate(), DebugEventStep);
2480 :
2481 5 : v8::Local<v8::Context> context = env.context();
2482 : // Create a function for testing stepping of named load.
2483 : v8::Local<v8::Function> foo = CompileFunction(
2484 : &env,
2485 : "function foo() {\n"
2486 : " var a = [];\n"
2487 : " var s = \"\";\n"
2488 : " for (var i = 0; i < 10; i++) {\n"
2489 : " var v = new V(i, i + 1);\n"
2490 : " v.y;\n"
2491 : " a.length;\n" // Special case: array length.
2492 : " s.length;\n" // Special case: string length.
2493 : " }\n"
2494 : "}\n"
2495 : "function V(x, y) {\n"
2496 : " this.x = x;\n"
2497 : " this.y = y;\n"
2498 : "}\n",
2499 5 : "foo");
2500 :
2501 : // Call function without any break points to ensure inlining is in place.
2502 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2503 :
2504 : // Set up break point and step through the function.
2505 5 : SetBreakPoint(foo, 4);
2506 5 : step_action = StepNext;
2507 5 : break_point_hit_count = 0;
2508 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2509 :
2510 : // With stepping all break locations are hit.
2511 5 : CHECK_EQ(65, break_point_hit_count);
2512 :
2513 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
2514 : CheckDebuggerUnloaded();
2515 5 : }
2516 :
2517 :
2518 5 : static void DoDebugStepNamedStoreLoop(int expected) {
2519 5 : DebugLocalContext env;
2520 10 : v8::HandleScope scope(env->GetIsolate());
2521 :
2522 : // Register a debug event listener which steps and counts.
2523 5 : SetDebugEventListener(env->GetIsolate(), DebugEventStep);
2524 :
2525 : // Create a function for testing stepping of named store.
2526 5 : v8::Local<v8::Context> context = env.context();
2527 : v8::Local<v8::Function> foo = CompileFunction(
2528 : &env,
2529 : "function foo() {\n"
2530 : " var a = {a:1};\n"
2531 : " for (var i = 0; i < 10; i++) {\n"
2532 : " a.a = 2\n"
2533 : " }\n"
2534 : "}\n",
2535 5 : "foo");
2536 :
2537 : // Call function without any break points to ensure inlining is in place.
2538 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2539 :
2540 : // Set up break point and step through the function.
2541 5 : SetBreakPoint(foo, 3);
2542 5 : step_action = StepNext;
2543 5 : break_point_hit_count = 0;
2544 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2545 :
2546 : // With stepping all expected break locations are hit.
2547 5 : CHECK_EQ(expected, break_point_hit_count);
2548 :
2549 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
2550 : CheckDebuggerUnloaded();
2551 5 : }
2552 :
2553 :
2554 : // Test of the stepping mechanism for named load in a loop.
2555 23723 : TEST(DebugStepNamedStoreLoop) { DoDebugStepNamedStoreLoop(34); }
2556 :
2557 : // Test the stepping mechanism with different ICs.
2558 23723 : TEST(DebugStepLinearMixedICs) {
2559 5 : DebugLocalContext env;
2560 10 : v8::HandleScope scope(env->GetIsolate());
2561 :
2562 : // Register a debug event listener which steps and counts.
2563 5 : SetDebugEventListener(env->GetIsolate(), DebugEventStep);
2564 :
2565 5 : v8::Local<v8::Context> context = env.context();
2566 : // Create a function for testing stepping.
2567 : v8::Local<v8::Function> foo = CompileFunction(&env,
2568 : "function bar() {};"
2569 : "function foo() {"
2570 : " var x;"
2571 : " var index='name';"
2572 : " var y = {};"
2573 5 : " a=1;b=2;x=a;y[index]=3;x=y[index];bar();}", "foo");
2574 :
2575 : // Run functions to allow them to get optimized.
2576 : CompileRun("a=0; b=0; bar(); foo();");
2577 :
2578 5 : SetBreakPoint(foo, 0);
2579 :
2580 5 : step_action = StepIn;
2581 5 : break_point_hit_count = 0;
2582 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2583 :
2584 : // With stepping all break locations are hit.
2585 5 : CHECK_EQ(10, break_point_hit_count);
2586 :
2587 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
2588 : CheckDebuggerUnloaded();
2589 :
2590 : // Register a debug event listener which just counts.
2591 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
2592 :
2593 5 : SetBreakPoint(foo, 0);
2594 5 : break_point_hit_count = 0;
2595 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2596 :
2597 : // Without stepping only active break points are hit.
2598 5 : CHECK_EQ(1, break_point_hit_count);
2599 :
2600 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
2601 : CheckDebuggerUnloaded();
2602 5 : }
2603 :
2604 :
2605 23723 : TEST(DebugStepDeclarations) {
2606 5 : DebugLocalContext env;
2607 10 : v8::HandleScope scope(env->GetIsolate());
2608 :
2609 : // Register a debug event listener which steps and counts.
2610 5 : SetDebugEventListener(env->GetIsolate(), DebugEventStep);
2611 :
2612 5 : v8::Local<v8::Context> context = env.context();
2613 : // Create a function for testing stepping. Run it to allow it to get
2614 : // optimized.
2615 : const char* src = "function foo() { "
2616 : " var a;"
2617 : " var b = 1;"
2618 : " var c = foo;"
2619 : " var d = Math.floor;"
2620 : " var e = b + d(1.2);"
2621 : "}"
2622 : "foo()";
2623 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2624 :
2625 5 : SetBreakPoint(foo, 0);
2626 :
2627 : // Stepping through the declarations.
2628 5 : step_action = StepIn;
2629 5 : break_point_hit_count = 0;
2630 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2631 5 : CHECK_EQ(5, break_point_hit_count);
2632 :
2633 : // Get rid of the debug event listener.
2634 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
2635 : CheckDebuggerUnloaded();
2636 5 : }
2637 :
2638 :
2639 23723 : TEST(DebugStepLocals) {
2640 5 : DebugLocalContext env;
2641 10 : v8::HandleScope scope(env->GetIsolate());
2642 :
2643 : // Register a debug event listener which steps and counts.
2644 5 : SetDebugEventListener(env->GetIsolate(), DebugEventStep);
2645 :
2646 5 : v8::Local<v8::Context> context = env.context();
2647 : // Create a function for testing stepping. Run it to allow it to get
2648 : // optimized.
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 : "foo()";
2657 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2658 :
2659 5 : SetBreakPoint(foo, 0);
2660 :
2661 : // Stepping through the declarations.
2662 5 : step_action = StepIn;
2663 5 : break_point_hit_count = 0;
2664 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
2665 5 : CHECK_EQ(5, break_point_hit_count);
2666 :
2667 : // Get rid of the debug event listener.
2668 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
2669 : CheckDebuggerUnloaded();
2670 5 : }
2671 :
2672 :
2673 23723 : TEST(DebugStepIf) {
2674 5 : DebugLocalContext env;
2675 5 : v8::Isolate* isolate = env->GetIsolate();
2676 10 : v8::HandleScope scope(isolate);
2677 :
2678 : // Register a debug event listener which steps and counts.
2679 5 : SetDebugEventListener(env->GetIsolate(), DebugEventStep);
2680 :
2681 5 : v8::Local<v8::Context> context = env.context();
2682 : // Create a function for testing stepping. Run it to allow it to get
2683 : // optimized.
2684 : const int argc = 1;
2685 : const char* src = "function foo(x) { "
2686 : " a = 1;"
2687 : " if (x) {"
2688 : " b = 1;"
2689 : " } else {"
2690 : " c = 1;"
2691 : " d = 1;"
2692 : " }"
2693 : "}"
2694 : "a=0; b=0; c=0; d=0; foo()";
2695 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2696 5 : SetBreakPoint(foo, 0);
2697 :
2698 : // Stepping through the true part.
2699 5 : step_action = StepIn;
2700 5 : break_point_hit_count = 0;
2701 : v8::Local<v8::Value> argv_true[argc] = {v8::True(isolate)};
2702 15 : foo->Call(context, env->Global(), argc, argv_true).ToLocalChecked();
2703 5 : CHECK_EQ(4, break_point_hit_count);
2704 :
2705 : // Stepping through the false part.
2706 5 : step_action = StepIn;
2707 5 : break_point_hit_count = 0;
2708 : v8::Local<v8::Value> argv_false[argc] = {v8::False(isolate)};
2709 15 : foo->Call(context, env->Global(), argc, argv_false).ToLocalChecked();
2710 5 : CHECK_EQ(5, break_point_hit_count);
2711 :
2712 : // Get rid of the debug event listener.
2713 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
2714 : CheckDebuggerUnloaded();
2715 5 : }
2716 :
2717 :
2718 23723 : TEST(DebugStepSwitch) {
2719 5 : DebugLocalContext env;
2720 5 : v8::Isolate* isolate = env->GetIsolate();
2721 10 : v8::HandleScope scope(isolate);
2722 :
2723 : // Register a debug event listener which steps and counts.
2724 5 : SetDebugEventListener(isolate, DebugEventStep);
2725 :
2726 5 : v8::Local<v8::Context> context = env.context();
2727 : // Create a function for testing stepping. Run it to allow it to get
2728 : // optimized.
2729 : const int argc = 1;
2730 : const char* src = "function foo(x) { "
2731 : " a = 1;"
2732 : " switch (x) {"
2733 : " case 1:"
2734 : " b = 1;"
2735 : " case 2:"
2736 : " c = 1;"
2737 : " break;"
2738 : " case 3:"
2739 : " d = 1;"
2740 : " e = 1;"
2741 : " f = 1;"
2742 : " break;"
2743 : " }"
2744 : "}"
2745 : "a=0; b=0; c=0; d=0; e=0; f=0; foo()";
2746 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2747 5 : SetBreakPoint(foo, 0);
2748 :
2749 : // One case with fall-through.
2750 5 : step_action = StepIn;
2751 5 : break_point_hit_count = 0;
2752 5 : v8::Local<v8::Value> argv_1[argc] = {v8::Number::New(isolate, 1)};
2753 15 : foo->Call(context, env->Global(), argc, argv_1).ToLocalChecked();
2754 5 : CHECK_EQ(6, break_point_hit_count);
2755 :
2756 : // Another case.
2757 5 : step_action = StepIn;
2758 5 : break_point_hit_count = 0;
2759 5 : v8::Local<v8::Value> argv_2[argc] = {v8::Number::New(isolate, 2)};
2760 15 : foo->Call(context, env->Global(), argc, argv_2).ToLocalChecked();
2761 5 : CHECK_EQ(5, break_point_hit_count);
2762 :
2763 : // Last case.
2764 5 : step_action = StepIn;
2765 5 : break_point_hit_count = 0;
2766 5 : v8::Local<v8::Value> argv_3[argc] = {v8::Number::New(isolate, 3)};
2767 15 : foo->Call(context, env->Global(), argc, argv_3).ToLocalChecked();
2768 5 : CHECK_EQ(7, break_point_hit_count);
2769 :
2770 : // Get rid of the debug event listener.
2771 5 : SetDebugEventListener(isolate, nullptr);
2772 : CheckDebuggerUnloaded();
2773 5 : }
2774 :
2775 :
2776 23723 : TEST(DebugStepWhile) {
2777 5 : DebugLocalContext env;
2778 5 : v8::Isolate* isolate = env->GetIsolate();
2779 10 : v8::HandleScope scope(isolate);
2780 :
2781 : // Register a debug event listener which steps and counts.
2782 5 : SetDebugEventListener(isolate, DebugEventStep);
2783 :
2784 5 : v8::Local<v8::Context> context = env.context();
2785 : // Create a function for testing stepping. Run it to allow it to get
2786 : // optimized.
2787 : const int argc = 1;
2788 : const char* src = "function foo(x) { "
2789 : " var a = 0;"
2790 : " while (a < x) {"
2791 : " a++;"
2792 : " }"
2793 : "}"
2794 : "foo()";
2795 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2796 5 : SetBreakPoint(foo, 8); // "var a = 0;"
2797 :
2798 : // Looping 0 times. We still should break at the while-condition once.
2799 5 : step_action = StepIn;
2800 5 : break_point_hit_count = 0;
2801 5 : v8::Local<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
2802 15 : foo->Call(context, env->Global(), argc, argv_0).ToLocalChecked();
2803 5 : CHECK_EQ(3, break_point_hit_count);
2804 :
2805 : // Looping 10 times.
2806 5 : step_action = StepIn;
2807 5 : break_point_hit_count = 0;
2808 5 : v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
2809 15 : foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
2810 5 : CHECK_EQ(23, break_point_hit_count);
2811 :
2812 : // Looping 100 times.
2813 5 : step_action = StepIn;
2814 5 : break_point_hit_count = 0;
2815 5 : v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
2816 15 : foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
2817 5 : CHECK_EQ(203, break_point_hit_count);
2818 :
2819 : // Get rid of the debug event listener.
2820 5 : SetDebugEventListener(isolate, nullptr);
2821 : CheckDebuggerUnloaded();
2822 5 : }
2823 :
2824 :
2825 23723 : TEST(DebugStepDoWhile) {
2826 5 : DebugLocalContext env;
2827 5 : v8::Isolate* isolate = env->GetIsolate();
2828 10 : v8::HandleScope scope(isolate);
2829 :
2830 : // Register a debug event listener which steps and counts.
2831 5 : SetDebugEventListener(isolate, DebugEventStep);
2832 :
2833 5 : v8::Local<v8::Context> context = env.context();
2834 : // Create a function for testing stepping. Run it to allow it to get
2835 : // optimized.
2836 : const int argc = 1;
2837 : const char* src = "function foo(x) { "
2838 : " var a = 0;"
2839 : " do {"
2840 : " a++;"
2841 : " } while (a < x)"
2842 : "}"
2843 : "foo()";
2844 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2845 5 : SetBreakPoint(foo, 8); // "var a = 0;"
2846 :
2847 : // Looping 0 times.
2848 5 : step_action = StepIn;
2849 5 : break_point_hit_count = 0;
2850 5 : v8::Local<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
2851 15 : foo->Call(context, env->Global(), argc, argv_0).ToLocalChecked();
2852 5 : CHECK_EQ(4, break_point_hit_count);
2853 :
2854 : // Looping 10 times.
2855 5 : step_action = StepIn;
2856 5 : break_point_hit_count = 0;
2857 5 : v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
2858 15 : foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
2859 5 : CHECK_EQ(22, break_point_hit_count);
2860 :
2861 : // Looping 100 times.
2862 5 : step_action = StepIn;
2863 5 : break_point_hit_count = 0;
2864 5 : v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
2865 15 : foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
2866 5 : CHECK_EQ(202, break_point_hit_count);
2867 :
2868 : // Get rid of the debug event listener.
2869 5 : SetDebugEventListener(isolate, nullptr);
2870 : CheckDebuggerUnloaded();
2871 5 : }
2872 :
2873 :
2874 23723 : TEST(DebugStepFor) {
2875 5 : DebugLocalContext env;
2876 5 : v8::Isolate* isolate = env->GetIsolate();
2877 10 : v8::HandleScope scope(isolate);
2878 :
2879 : // Register a debug event listener which steps and counts.
2880 5 : SetDebugEventListener(isolate, DebugEventStep);
2881 :
2882 5 : v8::Local<v8::Context> context = env.context();
2883 : // Create a function for testing stepping. Run it to allow it to get
2884 : // optimized.
2885 : const int argc = 1;
2886 : const char* src = "function foo(x) { "
2887 : " a = 1;"
2888 : " for (i = 0; i < x; i++) {"
2889 : " b = 1;"
2890 : " }"
2891 : "}"
2892 : "a=0; b=0; i=0; foo()";
2893 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2894 :
2895 5 : SetBreakPoint(foo, 8); // "a = 1;"
2896 :
2897 : // Looping 0 times.
2898 5 : step_action = StepIn;
2899 5 : break_point_hit_count = 0;
2900 5 : v8::Local<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
2901 15 : foo->Call(context, env->Global(), argc, argv_0).ToLocalChecked();
2902 5 : CHECK_EQ(4, break_point_hit_count);
2903 :
2904 : // Looping 10 times.
2905 5 : step_action = StepIn;
2906 5 : break_point_hit_count = 0;
2907 5 : v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
2908 15 : foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
2909 5 : CHECK_EQ(34, break_point_hit_count);
2910 :
2911 : // Looping 100 times.
2912 5 : step_action = StepIn;
2913 5 : break_point_hit_count = 0;
2914 5 : v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
2915 15 : foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
2916 5 : CHECK_EQ(304, break_point_hit_count);
2917 :
2918 : // Get rid of the debug event listener.
2919 5 : SetDebugEventListener(isolate, nullptr);
2920 : CheckDebuggerUnloaded();
2921 5 : }
2922 :
2923 :
2924 23723 : TEST(DebugStepForContinue) {
2925 5 : DebugLocalContext env;
2926 5 : v8::Isolate* isolate = env->GetIsolate();
2927 10 : v8::HandleScope scope(isolate);
2928 :
2929 : // Register a debug event listener which steps and counts.
2930 5 : SetDebugEventListener(isolate, DebugEventStep);
2931 :
2932 5 : v8::Local<v8::Context> context = env.context();
2933 : // Create a function for testing stepping. Run it to allow it to get
2934 : // optimized.
2935 : const int argc = 1;
2936 : const char* src = "function foo(x) { "
2937 : " var a = 0;"
2938 : " var b = 0;"
2939 : " var c = 0;"
2940 : " for (var i = 0; i < x; i++) {"
2941 : " a++;"
2942 : " if (a % 2 == 0) continue;"
2943 : " b++;"
2944 : " c++;"
2945 : " }"
2946 : " return b;"
2947 : "}"
2948 : "foo()";
2949 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2950 : v8::Local<v8::Value> result;
2951 5 : SetBreakPoint(foo, 8); // "var a = 0;"
2952 :
2953 : // Each loop generates 4 or 5 steps depending on whether a is equal.
2954 :
2955 : // Looping 10 times.
2956 5 : step_action = StepIn;
2957 5 : break_point_hit_count = 0;
2958 5 : v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
2959 15 : result = foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
2960 10 : CHECK_EQ(5, result->Int32Value(context).FromJust());
2961 5 : CHECK_EQ(62, break_point_hit_count);
2962 :
2963 : // Looping 100 times.
2964 5 : step_action = StepIn;
2965 5 : break_point_hit_count = 0;
2966 5 : v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
2967 15 : result = foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
2968 10 : CHECK_EQ(50, result->Int32Value(context).FromJust());
2969 5 : CHECK_EQ(557, break_point_hit_count);
2970 :
2971 : // Get rid of the debug event listener.
2972 5 : SetDebugEventListener(isolate, nullptr);
2973 : CheckDebuggerUnloaded();
2974 5 : }
2975 :
2976 :
2977 23723 : TEST(DebugStepForBreak) {
2978 5 : DebugLocalContext env;
2979 5 : v8::Isolate* isolate = env->GetIsolate();
2980 10 : v8::HandleScope scope(isolate);
2981 :
2982 : // Register a debug event listener which steps and counts.
2983 5 : SetDebugEventListener(isolate, DebugEventStep);
2984 :
2985 5 : v8::Local<v8::Context> context = env.context();
2986 : // Create a function for testing stepping. Run it to allow it to get
2987 : // optimized.
2988 : const int argc = 1;
2989 : const char* src = "function foo(x) { "
2990 : " var a = 0;"
2991 : " var b = 0;"
2992 : " var c = 0;"
2993 : " for (var i = 0; i < 1000; i++) {"
2994 : " a++;"
2995 : " if (a == x) break;"
2996 : " b++;"
2997 : " c++;"
2998 : " }"
2999 : " return b;"
3000 : "}"
3001 : "foo()";
3002 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3003 : v8::Local<v8::Value> result;
3004 5 : SetBreakPoint(foo, 8); // "var a = 0;"
3005 :
3006 : // Each loop generates 5 steps except for the last (when break is executed)
3007 : // which only generates 4.
3008 :
3009 : // Looping 10 times.
3010 5 : step_action = StepIn;
3011 5 : break_point_hit_count = 0;
3012 5 : v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
3013 15 : result = foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
3014 10 : CHECK_EQ(9, result->Int32Value(context).FromJust());
3015 5 : CHECK_EQ(64, break_point_hit_count);
3016 :
3017 : // Looping 100 times.
3018 5 : step_action = StepIn;
3019 5 : break_point_hit_count = 0;
3020 5 : v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
3021 15 : result = foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
3022 10 : CHECK_EQ(99, result->Int32Value(context).FromJust());
3023 5 : CHECK_EQ(604, break_point_hit_count);
3024 :
3025 : // Get rid of the debug event listener.
3026 5 : SetDebugEventListener(isolate, nullptr);
3027 : CheckDebuggerUnloaded();
3028 5 : }
3029 :
3030 :
3031 23723 : TEST(DebugStepForIn) {
3032 5 : DebugLocalContext env;
3033 10 : v8::HandleScope scope(env->GetIsolate());
3034 :
3035 : // Register a debug event listener which steps and counts.
3036 5 : SetDebugEventListener(env->GetIsolate(), DebugEventStep);
3037 :
3038 5 : v8::Local<v8::Context> context = env.context();
3039 : // Create a function for testing stepping. Run it to allow it to get
3040 : // optimized.
3041 : v8::Local<v8::Function> foo;
3042 : const char* src_1 = "function foo() { "
3043 : " var a = [1, 2];"
3044 : " for (x in a) {"
3045 : " b = 0;"
3046 : " }"
3047 : "}"
3048 : "foo()";
3049 5 : foo = CompileFunction(&env, src_1, "foo");
3050 5 : SetBreakPoint(foo, 0); // "var a = ..."
3051 :
3052 5 : step_action = StepIn;
3053 5 : break_point_hit_count = 0;
3054 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3055 5 : CHECK_EQ(8, break_point_hit_count);
3056 :
3057 : // Create a function for testing stepping. Run it to allow it to get
3058 : // optimized.
3059 : const char* src_2 = "function foo() { "
3060 : " var a = {a:[1, 2, 3]};"
3061 : " for (x in a.a) {"
3062 : " b = 0;"
3063 : " }"
3064 : "}"
3065 : "foo()";
3066 5 : foo = CompileFunction(&env, src_2, "foo");
3067 5 : SetBreakPoint(foo, 0); // "var a = ..."
3068 :
3069 5 : step_action = StepIn;
3070 5 : break_point_hit_count = 0;
3071 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3072 5 : CHECK_EQ(10, break_point_hit_count);
3073 :
3074 : // Get rid of the debug event listener.
3075 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
3076 : CheckDebuggerUnloaded();
3077 5 : }
3078 :
3079 :
3080 23723 : TEST(DebugStepWith) {
3081 5 : DebugLocalContext env;
3082 10 : v8::HandleScope scope(env->GetIsolate());
3083 :
3084 : // Register a debug event listener which steps and counts.
3085 5 : SetDebugEventListener(env->GetIsolate(), DebugEventStep);
3086 :
3087 5 : v8::Local<v8::Context> context = env.context();
3088 : // Create a function for testing stepping. Run it to allow it to get
3089 : // optimized.
3090 : const char* src = "function foo(x) { "
3091 : " var a = {};"
3092 : " with (a) {}"
3093 : " with (b) {}"
3094 : "}"
3095 : "foo()";
3096 25 : CHECK(env->Global()
3097 : ->Set(context, v8_str(env->GetIsolate(), "b"),
3098 : v8::Object::New(env->GetIsolate()))
3099 : .FromJust());
3100 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3101 : v8::Local<v8::Value> result;
3102 5 : SetBreakPoint(foo, 8); // "var a = {};"
3103 :
3104 5 : step_action = StepIn;
3105 5 : break_point_hit_count = 0;
3106 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3107 5 : CHECK_EQ(4, break_point_hit_count);
3108 :
3109 : // Get rid of the debug event listener.
3110 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
3111 : CheckDebuggerUnloaded();
3112 5 : }
3113 :
3114 :
3115 23723 : TEST(DebugConditional) {
3116 5 : DebugLocalContext env;
3117 5 : v8::Isolate* isolate = env->GetIsolate();
3118 10 : v8::HandleScope scope(isolate);
3119 :
3120 : // Register a debug event listener which steps and counts.
3121 5 : SetDebugEventListener(isolate, DebugEventStep);
3122 :
3123 5 : v8::Local<v8::Context> context = env.context();
3124 : // Create a function for testing stepping. Run it to allow it to get
3125 : // optimized.
3126 : const char* src =
3127 : "function foo(x) { "
3128 : " return x ? 1 : 2;"
3129 : "}"
3130 : "foo()";
3131 5 : v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3132 5 : SetBreakPoint(foo, 0); // "var a;"
3133 :
3134 5 : step_action = StepIn;
3135 5 : break_point_hit_count = 0;
3136 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3137 5 : CHECK_EQ(2, break_point_hit_count);
3138 :
3139 5 : step_action = StepIn;
3140 5 : break_point_hit_count = 0;
3141 : const int argc = 1;
3142 : v8::Local<v8::Value> argv_true[argc] = {v8::True(isolate)};
3143 15 : foo->Call(context, env->Global(), argc, argv_true).ToLocalChecked();
3144 5 : CHECK_EQ(2, break_point_hit_count);
3145 :
3146 : // Get rid of the debug event listener.
3147 5 : SetDebugEventListener(isolate, nullptr);
3148 : CheckDebuggerUnloaded();
3149 5 : }
3150 :
3151 :
3152 23723 : TEST(StepInOutSimple) {
3153 5 : DebugLocalContext env;
3154 10 : v8::HandleScope scope(env->GetIsolate());
3155 :
3156 : // Create a function for checking the function when hitting a break point.
3157 : frame_function_name = CompileFunction(&env,
3158 : frame_function_name_source,
3159 5 : "frame_function_name");
3160 :
3161 : // Register a debug event listener which steps and counts.
3162 5 : SetDebugEventListener(env->GetIsolate(), DebugEventStepSequence);
3163 :
3164 5 : v8::Local<v8::Context> context = env.context();
3165 : // Create a function for testing stepping. Run it to allow it to get
3166 : // optimized.
3167 : const char* src = "function a() {b();c();}; "
3168 : "function b() {c();}; "
3169 : "function c() {}; "
3170 : "a(); b(); c()";
3171 5 : v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3172 5 : SetBreakPoint(a, 0);
3173 :
3174 : // Step through invocation of a with step in.
3175 5 : step_action = StepIn;
3176 5 : break_point_hit_count = 0;
3177 5 : expected_step_sequence = "abcbaca";
3178 15 : a->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3179 10 : CHECK_EQ(StrLength(expected_step_sequence),
3180 : break_point_hit_count);
3181 :
3182 : // Step through invocation of a with step next.
3183 5 : step_action = StepNext;
3184 5 : break_point_hit_count = 0;
3185 5 : expected_step_sequence = "aaa";
3186 15 : a->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3187 10 : CHECK_EQ(StrLength(expected_step_sequence),
3188 : break_point_hit_count);
3189 :
3190 : // Step through invocation of a with step out.
3191 5 : step_action = StepOut;
3192 5 : break_point_hit_count = 0;
3193 5 : expected_step_sequence = "a";
3194 15 : a->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3195 10 : CHECK_EQ(StrLength(expected_step_sequence),
3196 : break_point_hit_count);
3197 :
3198 : // Get rid of the debug event listener.
3199 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
3200 : CheckDebuggerUnloaded();
3201 5 : }
3202 :
3203 :
3204 23723 : TEST(StepInOutTree) {
3205 5 : DebugLocalContext env;
3206 10 : v8::HandleScope scope(env->GetIsolate());
3207 :
3208 : // Create a function for checking the function when hitting a break point.
3209 : frame_function_name = CompileFunction(&env,
3210 : frame_function_name_source,
3211 5 : "frame_function_name");
3212 :
3213 : // Register a debug event listener which steps and counts.
3214 5 : SetDebugEventListener(env->GetIsolate(), DebugEventStepSequence);
3215 :
3216 5 : v8::Local<v8::Context> context = env.context();
3217 : // Create a function for testing stepping. Run it to allow it to get
3218 : // optimized.
3219 : const char* src = "function a() {b(c(d()),d());c(d());d()}; "
3220 : "function b(x,y) {c();}; "
3221 : "function c(x) {}; "
3222 : "function d() {}; "
3223 : "a(); b(); c(); d()";
3224 5 : v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3225 5 : SetBreakPoint(a, 0);
3226 :
3227 : // Step through invocation of a with step in.
3228 5 : step_action = StepIn;
3229 5 : break_point_hit_count = 0;
3230 5 : expected_step_sequence = "adacadabcbadacada";
3231 15 : a->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3232 10 : CHECK_EQ(StrLength(expected_step_sequence),
3233 : break_point_hit_count);
3234 :
3235 : // Step through invocation of a with step next.
3236 5 : step_action = StepNext;
3237 5 : break_point_hit_count = 0;
3238 5 : expected_step_sequence = "aaaa";
3239 15 : a->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3240 10 : CHECK_EQ(StrLength(expected_step_sequence),
3241 : break_point_hit_count);
3242 :
3243 : // Step through invocation of a with step out.
3244 5 : step_action = StepOut;
3245 5 : break_point_hit_count = 0;
3246 5 : expected_step_sequence = "a";
3247 15 : a->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3248 10 : CHECK_EQ(StrLength(expected_step_sequence),
3249 : break_point_hit_count);
3250 :
3251 : // Get rid of the debug event listener.
3252 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
3253 : CheckDebuggerUnloaded();
3254 5 : }
3255 :
3256 :
3257 23723 : TEST(StepInOutBranch) {
3258 5 : DebugLocalContext env;
3259 10 : v8::HandleScope scope(env->GetIsolate());
3260 :
3261 : // Create a function for checking the function when hitting a break point.
3262 : frame_function_name = CompileFunction(&env,
3263 : frame_function_name_source,
3264 5 : "frame_function_name");
3265 :
3266 : // Register a debug event listener which steps and counts.
3267 5 : SetDebugEventListener(env->GetIsolate(), DebugEventStepSequence);
3268 :
3269 5 : v8::Local<v8::Context> context = env.context();
3270 : // Create a function for testing stepping. Run it to allow it to get
3271 : // optimized.
3272 : const char* src = "function a() {b(false);c();}; "
3273 : "function b(x) {if(x){c();};}; "
3274 : "function c() {}; "
3275 : "a(); b(); c()";
3276 5 : v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3277 5 : SetBreakPoint(a, 0);
3278 :
3279 : // Step through invocation of a.
3280 5 : step_action = StepIn;
3281 5 : break_point_hit_count = 0;
3282 5 : expected_step_sequence = "abbaca";
3283 15 : a->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3284 10 : CHECK_EQ(StrLength(expected_step_sequence),
3285 : break_point_hit_count);
3286 :
3287 : // Get rid of the debug event listener.
3288 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
3289 : CheckDebuggerUnloaded();
3290 5 : }
3291 :
3292 :
3293 : // Test that step in does not step into native functions.
3294 23723 : TEST(DebugStepNatives) {
3295 5 : DebugLocalContext env;
3296 10 : v8::HandleScope scope(env->GetIsolate());
3297 :
3298 : // Create a function for testing stepping.
3299 : v8::Local<v8::Function> foo = CompileFunction(
3300 : &env,
3301 : "function foo(){debugger;Math.sin(1);}",
3302 5 : "foo");
3303 :
3304 : // Register a debug event listener which steps and counts.
3305 5 : SetDebugEventListener(env->GetIsolate(), DebugEventStep);
3306 :
3307 5 : v8::Local<v8::Context> context = env.context();
3308 5 : step_action = StepIn;
3309 5 : break_point_hit_count = 0;
3310 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3311 :
3312 : // With stepping all break locations are hit.
3313 5 : CHECK_EQ(3, break_point_hit_count);
3314 :
3315 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
3316 : CheckDebuggerUnloaded();
3317 :
3318 : // Register a debug event listener which just counts.
3319 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
3320 :
3321 5 : break_point_hit_count = 0;
3322 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3323 :
3324 : // Without stepping only active break points are hit.
3325 5 : CHECK_EQ(1, break_point_hit_count);
3326 :
3327 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
3328 : CheckDebuggerUnloaded();
3329 5 : }
3330 :
3331 :
3332 : // Test that step in works with function.apply.
3333 23723 : TEST(DebugStepFunctionApply) {
3334 5 : DebugLocalContext env;
3335 10 : v8::HandleScope scope(env->GetIsolate());
3336 :
3337 : // Create a function for testing stepping.
3338 : v8::Local<v8::Function> foo = CompileFunction(
3339 : &env,
3340 : "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3341 : "function foo(){ debugger; bar.apply(this, [1,2,3]); }",
3342 5 : "foo");
3343 :
3344 : // Register a debug event listener which steps and counts.
3345 5 : SetDebugEventListener(env->GetIsolate(), DebugEventStep);
3346 :
3347 5 : v8::Local<v8::Context> context = env.context();
3348 5 : step_action = StepIn;
3349 5 : break_point_hit_count = 0;
3350 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3351 :
3352 : // With stepping all break locations are hit.
3353 5 : CHECK_EQ(7, break_point_hit_count);
3354 :
3355 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
3356 : CheckDebuggerUnloaded();
3357 :
3358 : // Register a debug event listener which just counts.
3359 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
3360 :
3361 5 : break_point_hit_count = 0;
3362 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3363 :
3364 : // Without stepping only the debugger statement is hit.
3365 5 : CHECK_EQ(1, break_point_hit_count);
3366 :
3367 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
3368 : CheckDebuggerUnloaded();
3369 5 : }
3370 :
3371 :
3372 : // Test that step in works with function.call.
3373 23723 : TEST(DebugStepFunctionCall) {
3374 5 : DebugLocalContext env;
3375 5 : v8::Isolate* isolate = env->GetIsolate();
3376 10 : v8::HandleScope scope(isolate);
3377 :
3378 5 : v8::Local<v8::Context> context = env.context();
3379 : // Create a function for testing stepping.
3380 : v8::Local<v8::Function> foo = CompileFunction(
3381 : &env,
3382 : "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3383 : "function foo(a){ debugger;"
3384 : " if (a) {"
3385 : " bar.call(this, 1, 2, 3);"
3386 : " } else {"
3387 : " bar.call(this, 0);"
3388 : " }"
3389 : "}",
3390 5 : "foo");
3391 :
3392 : // Register a debug event listener which steps and counts.
3393 5 : SetDebugEventListener(isolate, DebugEventStep);
3394 5 : step_action = StepIn;
3395 :
3396 : // Check stepping where the if condition in bar is false.
3397 5 : break_point_hit_count = 0;
3398 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3399 5 : CHECK_EQ(6, break_point_hit_count);
3400 :
3401 : // Check stepping where the if condition in bar is true.
3402 5 : break_point_hit_count = 0;
3403 : const int argc = 1;
3404 : v8::Local<v8::Value> argv[argc] = {v8::True(isolate)};
3405 15 : foo->Call(context, env->Global(), argc, argv).ToLocalChecked();
3406 5 : CHECK_EQ(8, break_point_hit_count);
3407 :
3408 5 : SetDebugEventListener(isolate, nullptr);
3409 : CheckDebuggerUnloaded();
3410 :
3411 : // Register a debug event listener which just counts.
3412 5 : SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
3413 :
3414 5 : break_point_hit_count = 0;
3415 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3416 :
3417 : // Without stepping only the debugger statement is hit.
3418 5 : CHECK_EQ(1, break_point_hit_count);
3419 :
3420 5 : SetDebugEventListener(isolate, nullptr);
3421 : CheckDebuggerUnloaded();
3422 5 : }
3423 :
3424 :
3425 : // Test that step in works with Function.call.apply.
3426 23723 : TEST(DebugStepFunctionCallApply) {
3427 5 : DebugLocalContext env;
3428 5 : v8::Isolate* isolate = env->GetIsolate();
3429 10 : v8::HandleScope scope(isolate);
3430 :
3431 5 : v8::Local<v8::Context> context = env.context();
3432 : // Create a function for testing stepping.
3433 : v8::Local<v8::Function> foo =
3434 : CompileFunction(&env,
3435 : "function bar() { }"
3436 : "function foo(){ debugger;"
3437 : " Function.call.apply(bar);"
3438 : " Function.call.apply(Function.call, "
3439 : "[Function.call, bar]);"
3440 : "}",
3441 5 : "foo");
3442 :
3443 : // Register a debug event listener which steps and counts.
3444 5 : SetDebugEventListener(isolate, DebugEventStep);
3445 5 : step_action = StepIn;
3446 :
3447 5 : break_point_hit_count = 0;
3448 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3449 5 : CHECK_EQ(6, break_point_hit_count);
3450 :
3451 5 : SetDebugEventListener(isolate, nullptr);
3452 : CheckDebuggerUnloaded();
3453 :
3454 : // Register a debug event listener which just counts.
3455 5 : SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
3456 :
3457 5 : break_point_hit_count = 0;
3458 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3459 :
3460 : // Without stepping only the debugger statement is hit.
3461 5 : CHECK_EQ(1, break_point_hit_count);
3462 :
3463 5 : SetDebugEventListener(isolate, nullptr);
3464 : CheckDebuggerUnloaded();
3465 5 : }
3466 :
3467 :
3468 : // Tests that breakpoint will be hit if it's set in script.
3469 23723 : TEST(PauseInScript) {
3470 5 : DebugLocalContext env;
3471 10 : v8::HandleScope scope(env->GetIsolate());
3472 5 : env.ExposeDebug();
3473 :
3474 : // Register a debug event listener which counts.
3475 5 : SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
3476 :
3477 5 : v8::Local<v8::Context> context = env.context();
3478 : // Create a script that returns a function.
3479 : const char* src = "(function (evt) {})";
3480 : const char* script_name = "StepInHandlerTest";
3481 :
3482 : v8::ScriptOrigin origin(v8_str(env->GetIsolate(), script_name),
3483 10 : v8::Integer::New(env->GetIsolate(), 0));
3484 : v8::Local<v8::Script> script =
3485 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), src), &origin)
3486 5 : .ToLocalChecked();
3487 :
3488 : // Set breakpoint in the script.
3489 5 : SetScriptBreakPointByNameFromJS(env->GetIsolate(), script_name, 0, -1);
3490 5 : break_point_hit_count = 0;
3491 :
3492 5 : v8::Local<v8::Value> r = script->Run(context).ToLocalChecked();
3493 :
3494 5 : CHECK(r->IsFunction());
3495 5 : CHECK_EQ(1, break_point_hit_count);
3496 :
3497 : // Get rid of the debug event listener.
3498 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
3499 : CheckDebuggerUnloaded();
3500 5 : }
3501 :
3502 :
3503 245 : static void DebugEventCounterCheck(int caught, int uncaught, int message) {
3504 245 : CHECK_EQ(caught, exception_hit_count);
3505 245 : CHECK_EQ(uncaught, uncaught_exception_hit_count);
3506 245 : CHECK_EQ(message, message_callback_count);
3507 245 : }
3508 :
3509 :
3510 : // Test break on exceptions. For each exception break combination the number
3511 : // of debug event exception callbacks and message callbacks are collected. The
3512 : // number of debug event exception callbacks are used to check that the
3513 : // debugger is called correctly and the number of message callbacks is used to
3514 : // check that uncaught exceptions are still returned even if there is a break
3515 : // for them.
3516 23723 : TEST(BreakOnException) {
3517 5 : DebugLocalContext env;
3518 10 : v8::HandleScope scope(env->GetIsolate());
3519 5 : env.ExposeDebug();
3520 :
3521 5 : v8::Local<v8::Context> context = env.context();
3522 : // Create functions for testing break on exception.
3523 5 : CompileFunction(&env, "function throws(){throw 1;}", "throws");
3524 : v8::Local<v8::Function> caught =
3525 : CompileFunction(&env,
3526 : "function caught(){try {throws();} catch(e) {};}",
3527 5 : "caught");
3528 : v8::Local<v8::Function> notCaught =
3529 5 : CompileFunction(&env, "function notCaught(){throws();}", "notCaught");
3530 : v8::Local<v8::Function> notCaughtFinally = CompileFunction(
3531 : &env, "function notCaughtFinally(){try{throws();}finally{}}",
3532 5 : "notCaughtFinally");
3533 : // In this edge case, even though this finally does not propagate the
3534 : // exception, the debugger considers this uncaught, since we want to break
3535 : // at the first throw for the general case where finally implicitly rethrows.
3536 : v8::Local<v8::Function> edgeCaseFinally = CompileFunction(
3537 : &env, "function caughtFinally(){L:try{throws();}finally{break L;}}",
3538 5 : "caughtFinally");
3539 :
3540 5 : env->GetIsolate()->AddMessageListener(MessageCallbackCount);
3541 5 : SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
3542 :
3543 : // Initial state should be no break on exceptions.
3544 : DebugEventCounterClear();
3545 : MessageCallbackCountClear();
3546 15 : caught->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3547 5 : DebugEventCounterCheck(0, 0, 0);
3548 15 : CHECK(notCaught->Call(context, env->Global(), 0, nullptr).IsEmpty());
3549 5 : DebugEventCounterCheck(0, 0, 1);
3550 15 : CHECK(notCaughtFinally->Call(context, env->Global(), 0, nullptr).IsEmpty());
3551 5 : DebugEventCounterCheck(0, 0, 2);
3552 15 : edgeCaseFinally->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3553 5 : DebugEventCounterCheck(0, 0, 2);
3554 :
3555 : // No break on exception
3556 : DebugEventCounterClear();
3557 : MessageCallbackCountClear();
3558 5 : ChangeBreakOnException(false, false);
3559 15 : caught->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3560 5 : DebugEventCounterCheck(0, 0, 0);
3561 15 : CHECK(notCaught->Call(context, env->Global(), 0, nullptr).IsEmpty());
3562 5 : DebugEventCounterCheck(0, 0, 1);
3563 15 : CHECK(notCaughtFinally->Call(context, env->Global(), 0, nullptr).IsEmpty());
3564 5 : DebugEventCounterCheck(0, 0, 2);
3565 15 : edgeCaseFinally->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3566 5 : DebugEventCounterCheck(0, 0, 2);
3567 :
3568 : // Break on uncaught exception
3569 : DebugEventCounterClear();
3570 : MessageCallbackCountClear();
3571 5 : ChangeBreakOnException(false, true);
3572 15 : caught->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3573 5 : DebugEventCounterCheck(0, 0, 0);
3574 15 : CHECK(notCaught->Call(context, env->Global(), 0, nullptr).IsEmpty());
3575 5 : DebugEventCounterCheck(1, 1, 1);
3576 15 : CHECK(notCaughtFinally->Call(context, env->Global(), 0, nullptr).IsEmpty());
3577 5 : DebugEventCounterCheck(2, 2, 2);
3578 15 : edgeCaseFinally->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3579 5 : DebugEventCounterCheck(3, 3, 2);
3580 :
3581 : // Break on exception and uncaught exception
3582 : DebugEventCounterClear();
3583 : MessageCallbackCountClear();
3584 5 : ChangeBreakOnException(true, true);
3585 15 : caught->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3586 5 : DebugEventCounterCheck(1, 0, 0);
3587 15 : CHECK(notCaught->Call(context, env->Global(), 0, nullptr).IsEmpty());
3588 5 : DebugEventCounterCheck(2, 1, 1);
3589 15 : CHECK(notCaughtFinally->Call(context, env->Global(), 0, nullptr).IsEmpty());
3590 5 : DebugEventCounterCheck(3, 2, 2);
3591 15 : edgeCaseFinally->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3592 5 : DebugEventCounterCheck(4, 3, 2);
3593 :
3594 : // Break on exception
3595 : DebugEventCounterClear();
3596 : MessageCallbackCountClear();
3597 5 : ChangeBreakOnException(true, false);
3598 15 : caught->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3599 5 : DebugEventCounterCheck(1, 0, 0);
3600 15 : CHECK(notCaught->Call(context, env->Global(), 0, nullptr).IsEmpty());
3601 5 : DebugEventCounterCheck(2, 1, 1);
3602 15 : CHECK(notCaughtFinally->Call(context, env->Global(), 0, nullptr).IsEmpty());
3603 5 : DebugEventCounterCheck(3, 2, 2);
3604 15 : edgeCaseFinally->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3605 5 : DebugEventCounterCheck(4, 3, 2);
3606 :
3607 : // No break on exception using JavaScript
3608 : DebugEventCounterClear();
3609 : MessageCallbackCountClear();
3610 5 : ChangeBreakOnExceptionFromJS(env->GetIsolate(), false, false);
3611 15 : caught->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3612 5 : DebugEventCounterCheck(0, 0, 0);
3613 15 : CHECK(notCaught->Call(context, env->Global(), 0, nullptr).IsEmpty());
3614 5 : DebugEventCounterCheck(0, 0, 1);
3615 15 : CHECK(notCaughtFinally->Call(context, env->Global(), 0, nullptr).IsEmpty());
3616 5 : DebugEventCounterCheck(0, 0, 2);
3617 15 : edgeCaseFinally->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3618 5 : DebugEventCounterCheck(0, 0, 2);
3619 :
3620 : // Break on uncaught exception using JavaScript
3621 : DebugEventCounterClear();
3622 : MessageCallbackCountClear();
3623 5 : ChangeBreakOnExceptionFromJS(env->GetIsolate(), false, true);
3624 15 : caught->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3625 5 : DebugEventCounterCheck(0, 0, 0);
3626 15 : CHECK(notCaught->Call(context, env->Global(), 0, nullptr).IsEmpty());
3627 5 : DebugEventCounterCheck(1, 1, 1);
3628 15 : CHECK(notCaughtFinally->Call(context, env->Global(), 0, nullptr).IsEmpty());
3629 5 : DebugEventCounterCheck(2, 2, 2);
3630 15 : edgeCaseFinally->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3631 5 : DebugEventCounterCheck(3, 3, 2);
3632 :
3633 : // Break on exception and uncaught exception using JavaScript
3634 : DebugEventCounterClear();
3635 : MessageCallbackCountClear();
3636 5 : ChangeBreakOnExceptionFromJS(env->GetIsolate(), true, true);
3637 15 : caught->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3638 5 : DebugEventCounterCheck(1, 0, 0);
3639 15 : CHECK(notCaught->Call(context, env->Global(), 0, nullptr).IsEmpty());
3640 5 : DebugEventCounterCheck(2, 1, 1);
3641 15 : CHECK(notCaughtFinally->Call(context, env->Global(), 0, nullptr).IsEmpty());
3642 5 : DebugEventCounterCheck(3, 2, 2);
3643 15 : edgeCaseFinally->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3644 5 : DebugEventCounterCheck(4, 3, 2);
3645 :
3646 : // Break on exception using JavaScript
3647 : DebugEventCounterClear();
3648 : MessageCallbackCountClear();
3649 5 : ChangeBreakOnExceptionFromJS(env->GetIsolate(), true, false);
3650 15 : caught->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3651 5 : DebugEventCounterCheck(1, 0, 0);
3652 15 : CHECK(notCaught->Call(context, env->Global(), 0, nullptr).IsEmpty());
3653 5 : DebugEventCounterCheck(2, 1, 1);
3654 15 : CHECK(notCaughtFinally->Call(context, env->Global(), 0, nullptr).IsEmpty());
3655 5 : DebugEventCounterCheck(3, 2, 2);
3656 15 : edgeCaseFinally->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3657 5 : DebugEventCounterCheck(4, 3, 2);
3658 :
3659 : // No break on exception using native API
3660 : DebugEventCounterClear();
3661 : MessageCallbackCountClear();
3662 : ChangeBreakOnExceptionFromAPI(env->GetIsolate(),
3663 5 : v8::debug::NoBreakOnException);
3664 15 : caught->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3665 5 : DebugEventCounterCheck(0, 0, 0);
3666 15 : CHECK(notCaught->Call(context, env->Global(), 0, nullptr).IsEmpty());
3667 5 : DebugEventCounterCheck(0, 0, 1);
3668 15 : CHECK(notCaughtFinally->Call(context, env->Global(), 0, nullptr).IsEmpty());
3669 5 : DebugEventCounterCheck(0, 0, 2);
3670 15 : edgeCaseFinally->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3671 5 : DebugEventCounterCheck(0, 0, 2);
3672 :
3673 : // // Break on uncaught exception using native API
3674 : DebugEventCounterClear();
3675 : MessageCallbackCountClear();
3676 : ChangeBreakOnExceptionFromAPI(env->GetIsolate(),
3677 5 : v8::debug::BreakOnUncaughtException);
3678 15 : caught->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3679 5 : DebugEventCounterCheck(0, 0, 0);
3680 15 : CHECK(notCaught->Call(context, env->Global(), 0, nullptr).IsEmpty());
3681 5 : DebugEventCounterCheck(1, 1, 1);
3682 15 : CHECK(notCaughtFinally->Call(context, env->Global(), 0, nullptr).IsEmpty());
3683 5 : DebugEventCounterCheck(2, 2, 2);
3684 15 : edgeCaseFinally->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3685 5 : DebugEventCounterCheck(3, 3, 2);
3686 :
3687 : // // Break on exception and uncaught exception using native API
3688 : DebugEventCounterClear();
3689 : MessageCallbackCountClear();
3690 : ChangeBreakOnExceptionFromAPI(env->GetIsolate(),
3691 5 : v8::debug::BreakOnAnyException);
3692 15 : caught->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3693 5 : DebugEventCounterCheck(1, 0, 0);
3694 15 : CHECK(notCaught->Call(context, env->Global(), 0, nullptr).IsEmpty());
3695 5 : DebugEventCounterCheck(2, 1, 1);
3696 15 : CHECK(notCaughtFinally->Call(context, env->Global(), 0, nullptr).IsEmpty());
3697 5 : DebugEventCounterCheck(3, 2, 2);
3698 15 : edgeCaseFinally->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3699 5 : DebugEventCounterCheck(4, 3, 2);
3700 :
3701 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
3702 : CheckDebuggerUnloaded();
3703 5 : env->GetIsolate()->RemoveMessageListeners(MessageCallbackCount);
3704 5 : }
3705 :
3706 :
3707 5 : static void try_finally_original_message(v8::Local<v8::Message> message,
3708 : v8::Local<v8::Value> data) {
3709 5 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
3710 10 : CHECK_EQ(2, message->GetLineNumber(context).FromJust());
3711 10 : CHECK_EQ(2, message->GetStartColumn(context).FromJust());
3712 5 : message_callback_count++;
3713 5 : }
3714 :
3715 :
3716 23723 : TEST(TryFinallyOriginalMessage) {
3717 : // Test that the debugger plays nicely with the pending message.
3718 5 : message_callback_count = 0;
3719 : DebugEventCounterClear();
3720 5 : DebugLocalContext env;
3721 5 : v8::Isolate* isolate = CcTest::isolate();
3722 5 : isolate->AddMessageListener(try_finally_original_message);
3723 5 : SetDebugEventListener(isolate, DebugEventCounter);
3724 5 : ChangeBreakOnException(true, true);
3725 10 : v8::HandleScope scope(isolate);
3726 : CompileRun(
3727 : "try {\n"
3728 : " throw 1;\n"
3729 : "} finally {\n"
3730 : "}\n");
3731 5 : DebugEventCounterCheck(1, 1, 1);
3732 5 : SetDebugEventListener(isolate, nullptr);
3733 5 : isolate->RemoveMessageListeners(try_finally_original_message);
3734 5 : }
3735 :
3736 :
3737 : // Test break on exception from compiler errors. When compiling using
3738 : // v8::Script::Compile there is no JavaScript stack whereas when compiling using
3739 : // eval there are JavaScript frames.
3740 23723 : TEST(BreakOnCompileException) {
3741 5 : DebugLocalContext env;
3742 10 : v8::HandleScope scope(env->GetIsolate());
3743 :
3744 5 : v8::Local<v8::Context> context = env.context();
3745 : // For this test, we want to break on uncaught exceptions:
3746 5 : ChangeBreakOnException(false, true);
3747 :
3748 : // Create a function for checking the function when hitting a break point.
3749 5 : frame_count = CompileFunction(&env, frame_count_source, "frame_count");
3750 :
3751 5 : env->GetIsolate()->AddMessageListener(MessageCallbackCount);
3752 5 : SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
3753 :
3754 : DebugEventCounterClear();
3755 : MessageCallbackCountClear();
3756 :
3757 : // Check initial state.
3758 5 : CHECK_EQ(0, exception_hit_count);
3759 5 : CHECK_EQ(0, uncaught_exception_hit_count);
3760 5 : CHECK_EQ(0, message_callback_count);
3761 5 : CHECK_EQ(-1, last_js_stack_height);
3762 :
3763 : // Throws SyntaxError: Unexpected end of input
3764 10 : CHECK(
3765 : v8::Script::Compile(context, v8_str(env->GetIsolate(), "+++")).IsEmpty());
3766 : // Exceptions with no stack are skipped.
3767 5 : CHECK_EQ(0, exception_hit_count);
3768 5 : CHECK_EQ(0, uncaught_exception_hit_count);
3769 5 : CHECK_EQ(1, message_callback_count);
3770 5 : CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
3771 :
3772 : // Throws SyntaxError: Unexpected identifier
3773 10 : CHECK(
3774 : v8::Script::Compile(context, v8_str(env->GetIsolate(), "x x")).IsEmpty());
3775 : // Exceptions with no stack are skipped.
3776 5 : CHECK_EQ(0, exception_hit_count);
3777 5 : CHECK_EQ(0, uncaught_exception_hit_count);
3778 5 : CHECK_EQ(2, message_callback_count);
3779 5 : CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
3780 :
3781 : // Throws SyntaxError: Unexpected end of input
3782 15 : CHECK(v8::Script::Compile(context, v8_str(env->GetIsolate(), "eval('+++')"))
3783 : .ToLocalChecked()
3784 : ->Run(context)
3785 : .IsEmpty());
3786 5 : CHECK_EQ(1, exception_hit_count);
3787 5 : CHECK_EQ(1, uncaught_exception_hit_count);
3788 5 : CHECK_EQ(3, message_callback_count);
3789 5 : CHECK_EQ(1, last_js_stack_height);
3790 :
3791 : // Throws SyntaxError: Unexpected identifier
3792 15 : CHECK(v8::Script::Compile(context, v8_str(env->GetIsolate(), "eval('x x')"))
3793 : .ToLocalChecked()
3794 : ->Run(context)
3795 : .IsEmpty());
3796 5 : CHECK_EQ(2, exception_hit_count);
3797 5 : CHECK_EQ(2, uncaught_exception_hit_count);
3798 5 : CHECK_EQ(4, message_callback_count);
3799 5 : CHECK_EQ(1, last_js_stack_height);
3800 5 : }
3801 :
3802 :
3803 23723 : TEST(StepWithException) {
3804 5 : DebugLocalContext env;
3805 10 : v8::HandleScope scope(env->GetIsolate());
3806 :
3807 : // For this test, we want to break on uncaught exceptions:
3808 5 : ChangeBreakOnException(false, true);
3809 :
3810 : // Create a function for checking the function when hitting a break point.
3811 : frame_function_name = CompileFunction(&env,
3812 : frame_function_name_source,
3813 5 : "frame_function_name");
3814 :
3815 : // Register a debug event listener which steps and counts.
3816 5 : SetDebugEventListener(env->GetIsolate(), DebugEventStepSequence);
3817 :
3818 5 : v8::Local<v8::Context> context = env.context();
3819 : // Create functions for testing stepping.
3820 : const char* src = "function a() { n(); }; "
3821 : "function b() { c(); }; "
3822 : "function c() { n(); }; "
3823 : "function d() { x = 1; try { e(); } catch(x) { x = 2; } }; "
3824 : "function e() { n(); }; "
3825 : "function f() { x = 1; try { g(); } catch(x) { x = 2; } }; "
3826 : "function g() { h(); }; "
3827 : "function h() { x = 1; throw 1; }; ";
3828 :
3829 : // Step through invocation of a.
3830 5 : ClearStepping();
3831 5 : v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3832 5 : SetBreakPoint(a, 0);
3833 5 : step_action = StepIn;
3834 5 : break_point_hit_count = 0;
3835 5 : expected_step_sequence = "aa";
3836 15 : CHECK(a->Call(context, env->Global(), 0, nullptr).IsEmpty());
3837 10 : CHECK_EQ(StrLength(expected_step_sequence),
3838 : break_point_hit_count);
3839 :
3840 : // Step through invocation of b + c.
3841 5 : ClearStepping();
3842 5 : v8::Local<v8::Function> b = CompileFunction(&env, src, "b");
3843 5 : SetBreakPoint(b, 0);
3844 5 : step_action = StepIn;
3845 5 : break_point_hit_count = 0;
3846 5 : expected_step_sequence = "bcc";
3847 15 : CHECK(b->Call(context, env->Global(), 0, nullptr).IsEmpty());
3848 10 : CHECK_EQ(StrLength(expected_step_sequence),
3849 : break_point_hit_count);
3850 :
3851 : // Step through invocation of d + e.
3852 5 : ClearStepping();
3853 5 : v8::Local<v8::Function> d = CompileFunction(&env, src, "d");
3854 5 : SetBreakPoint(d, 0);
3855 5 : ChangeBreakOnException(false, true);
3856 5 : step_action = StepIn;
3857 5 : break_point_hit_count = 0;
3858 5 : expected_step_sequence = "ddedd";
3859 15 : d->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3860 10 : CHECK_EQ(StrLength(expected_step_sequence),
3861 : break_point_hit_count);
3862 :
3863 : // Step through invocation of d + e now with break on caught exceptions.
3864 5 : ChangeBreakOnException(true, true);
3865 5 : step_action = StepIn;
3866 5 : break_point_hit_count = 0;
3867 5 : expected_step_sequence = "ddeedd";
3868 15 : d->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3869 10 : CHECK_EQ(StrLength(expected_step_sequence),
3870 : break_point_hit_count);
3871 :
3872 : // Step through invocation of f + g + h.
3873 5 : ClearStepping();
3874 5 : v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
3875 5 : SetBreakPoint(f, 0);
3876 5 : ChangeBreakOnException(false, true);
3877 5 : step_action = StepIn;
3878 5 : break_point_hit_count = 0;
3879 5 : expected_step_sequence = "ffghhff";
3880 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3881 10 : CHECK_EQ(StrLength(expected_step_sequence),
3882 : break_point_hit_count);
3883 :
3884 : // Step through invocation of f + g + h now with break on caught exceptions.
3885 5 : ChangeBreakOnException(true, true);
3886 5 : step_action = StepIn;
3887 5 : break_point_hit_count = 0;
3888 5 : expected_step_sequence = "ffghhhff";
3889 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3890 10 : CHECK_EQ(StrLength(expected_step_sequence),
3891 : break_point_hit_count);
3892 :
3893 : // Get rid of the debug event listener.
3894 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
3895 : CheckDebuggerUnloaded();
3896 5 : }
3897 :
3898 :
3899 23723 : TEST(DebugBreak) {
3900 5 : i::FLAG_stress_compaction = false;
3901 : #ifdef VERIFY_HEAP
3902 : i::FLAG_verify_heap = true;
3903 : #endif
3904 5 : DebugLocalContext env;
3905 5 : v8::Isolate* isolate = env->GetIsolate();
3906 10 : v8::HandleScope scope(isolate);
3907 :
3908 : // Register a debug event listener which sets the break flag and counts.
3909 5 : SetDebugEventListener(isolate, DebugEventBreak);
3910 :
3911 5 : v8::Local<v8::Context> context = env.context();
3912 : // Create a function for testing stepping.
3913 : const char* src = "function f0() {}"
3914 : "function f1(x1) {}"
3915 : "function f2(x1,x2) {}"
3916 : "function f3(x1,x2,x3) {}";
3917 5 : v8::Local<v8::Function> f0 = CompileFunction(&env, src, "f0");
3918 5 : v8::Local<v8::Function> f1 = CompileFunction(&env, src, "f1");
3919 5 : v8::Local<v8::Function> f2 = CompileFunction(&env, src, "f2");
3920 5 : v8::Local<v8::Function> f3 = CompileFunction(&env, src, "f3");
3921 :
3922 : // Call the function to make sure it is compiled.
3923 : v8::Local<v8::Value> argv[] = {
3924 : v8::Number::New(isolate, 1), v8::Number::New(isolate, 1),
3925 20 : v8::Number::New(isolate, 1), v8::Number::New(isolate, 1)};
3926 :
3927 : // Call all functions to make sure that they are compiled.
3928 15 : f0->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3929 15 : f1->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3930 15 : f2->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3931 15 : f3->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3932 :
3933 : // Set the debug break flag.
3934 5 : v8::debug::DebugBreak(env->GetIsolate());
3935 :
3936 : // Call all functions with different argument count.
3937 5 : break_point_hit_count = 0;
3938 25 : for (unsigned int i = 0; i < arraysize(argv); i++) {
3939 80 : f0->Call(context, env->Global(), i, argv).ToLocalChecked();
3940 60 : f1->Call(context, env->Global(), i, argv).ToLocalChecked();
3941 60 : f2->Call(context, env->Global(), i, argv).ToLocalChecked();
3942 60 : f3->Call(context, env->Global(), i, argv).ToLocalChecked();
3943 : }
3944 :
3945 : // One break for each function called.
3946 10 : CHECK_EQ(4 * arraysize(argv), break_point_hit_count);
3947 :
3948 : // Get rid of the debug event listener.
3949 5 : SetDebugEventListener(isolate, nullptr);
3950 : CheckDebuggerUnloaded();
3951 5 : }
3952 :
3953 :
3954 : // Test to ensure that JavaScript code keeps running while the debug break
3955 : // through the stack limit flag is set but breaks are disabled.
3956 23723 : TEST(DisableBreak) {
3957 5 : DebugLocalContext env;
3958 10 : v8::HandleScope scope(env->GetIsolate());
3959 :
3960 : // Register a debug event listener which sets the break flag and counts.
3961 5 : SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
3962 :
3963 5 : v8::Local<v8::Context> context = env.context();
3964 : // Create a function for testing stepping.
3965 : const char* src = "function f() {g()};function g(){i=0; while(i<10){i++}}";
3966 5 : v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
3967 :
3968 : // Set, test and cancel debug break.
3969 5 : v8::debug::DebugBreak(env->GetIsolate());
3970 5 : v8::debug::CancelDebugBreak(env->GetIsolate());
3971 :
3972 : // Set the debug break flag.
3973 5 : v8::debug::DebugBreak(env->GetIsolate());
3974 :
3975 : // Call all functions with different argument count.
3976 5 : break_point_hit_count = 0;
3977 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3978 5 : CHECK_EQ(1, break_point_hit_count);
3979 :
3980 : {
3981 5 : v8::debug::DebugBreak(env->GetIsolate());
3982 5 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
3983 : v8::internal::DisableBreak disable_break(isolate->debug());
3984 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3985 5 : CHECK_EQ(1, break_point_hit_count);
3986 : }
3987 :
3988 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
3989 5 : CHECK_EQ(2, break_point_hit_count);
3990 :
3991 : // Get rid of the debug event listener.
3992 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
3993 : CheckDebuggerUnloaded();
3994 5 : }
3995 :
3996 23723 : TEST(DisableDebuggerStatement) {
3997 5 : DebugLocalContext env;
3998 10 : v8::HandleScope scope(env->GetIsolate());
3999 :
4000 : // Register a debug event listener which sets the break flag and counts.
4001 5 : SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
4002 : CompileRun("debugger;");
4003 5 : CHECK_EQ(1, break_point_hit_count);
4004 :
4005 : // Check that we ignore debugger statement when breakpoints aren't active.
4006 5 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
4007 : isolate->debug()->set_break_points_active(false);
4008 : CompileRun("debugger;");
4009 5 : CHECK_EQ(1, break_point_hit_count);
4010 5 : }
4011 :
4012 : static const char* kSimpleExtensionSource =
4013 : "(function Foo() {"
4014 : " return 4;"
4015 : "})() ";
4016 :
4017 : // http://crbug.com/28933
4018 : // Test that debug break is disabled when bootstrapper is active.
4019 23723 : TEST(NoBreakWhenBootstrapping) {
4020 5 : v8::Isolate* isolate = CcTest::isolate();
4021 5 : v8::HandleScope scope(isolate);
4022 :
4023 : // Register a debug event listener which sets the break flag and counts.
4024 5 : SetDebugEventListener(isolate, DebugEventCounter);
4025 :
4026 : // Set the debug break flag.
4027 5 : v8::debug::DebugBreak(isolate);
4028 5 : break_point_hit_count = 0;
4029 : {
4030 : // Create a context with an extension to make sure that some JavaScript
4031 : // code is executed during bootstrapping.
4032 : v8::RegisterExtension(new v8::Extension("simpletest",
4033 5 : kSimpleExtensionSource));
4034 5 : const char* extension_names[] = { "simpletest" };
4035 : v8::ExtensionConfiguration extensions(1, extension_names);
4036 5 : v8::HandleScope handle_scope(isolate);
4037 5 : v8::Context::New(isolate, &extensions);
4038 : }
4039 : // Check that no DebugBreak events occurred during the context creation.
4040 5 : CHECK_EQ(0, break_point_hit_count);
4041 :
4042 : // Get rid of the debug event listener.
4043 5 : SetDebugEventListener(isolate, nullptr);
4044 5 : CheckDebuggerUnloaded();
4045 5 : }
4046 :
4047 :
4048 30 : static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
4049 30 : v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
4050 30 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
4051 120 : CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 0),
4052 : v8_str(info.GetIsolate(), "a"))
4053 : .FromJust());
4054 120 : CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 1),
4055 : v8_str(info.GetIsolate(), "b"))
4056 : .FromJust());
4057 120 : CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 2),
4058 : v8_str(info.GetIsolate(), "c"))
4059 : .FromJust());
4060 : info.GetReturnValue().Set(result);
4061 30 : }
4062 :
4063 :
4064 30 : static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
4065 : v8::Isolate* isolate = info.GetIsolate();
4066 30 : v8::Local<v8::Array> result = v8::Array::New(isolate, 2);
4067 30 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
4068 120 : CHECK(result->Set(context, v8::Integer::New(isolate, 0),
4069 : v8::Number::New(isolate, 1))
4070 : .FromJust());
4071 120 : CHECK(result->Set(context, v8::Integer::New(isolate, 1),
4072 : v8::Number::New(isolate, 10))
4073 : .FromJust());
4074 : info.GetReturnValue().Set(result);
4075 30 : }
4076 :
4077 :
4078 0 : static void NamedGetter(v8::Local<v8::Name> name,
4079 : const v8::PropertyCallbackInfo<v8::Value>& info) {
4080 0 : if (name->IsSymbol()) return;
4081 0 : v8::String::Utf8Value n(CcTest::isolate(), v8::Local<v8::String>::Cast(name));
4082 0 : if (strcmp(*n, "a") == 0) {
4083 0 : info.GetReturnValue().Set(v8_str(info.GetIsolate(), "AA"));
4084 0 : return;
4085 0 : } else if (strcmp(*n, "b") == 0) {
4086 0 : info.GetReturnValue().Set(v8_str(info.GetIsolate(), "BB"));
4087 : return;
4088 0 : } else if (strcmp(*n, "c") == 0) {
4089 0 : info.GetReturnValue().Set(v8_str(info.GetIsolate(), "CC"));
4090 : return;
4091 : } else {
4092 : info.GetReturnValue().SetUndefined();
4093 0 : return;
4094 : }
4095 : info.GetReturnValue().Set(name);
4096 : }
4097 :
4098 :
4099 40 : static void IndexedGetter(uint32_t index,
4100 : const v8::PropertyCallbackInfo<v8::Value>& info) {
4101 40 : info.GetReturnValue().Set(static_cast<double>(index + 1));
4102 40 : }
4103 :
4104 :
4105 23723 : TEST(InterceptorPropertyMirror) {
4106 : // Create a V8 environment with debug access.
4107 5 : DebugLocalContext env;
4108 5 : v8::Isolate* isolate = env->GetIsolate();
4109 10 : v8::HandleScope scope(isolate);
4110 5 : env.ExposeDebug();
4111 :
4112 5 : v8::Local<v8::Context> context = env.context();
4113 : // Create object with named interceptor.
4114 5 : v8::Local<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
4115 : named->SetHandler(v8::NamedPropertyHandlerConfiguration(
4116 5 : NamedGetter, nullptr, nullptr, nullptr, NamedEnum));
4117 25 : CHECK(env->Global()
4118 : ->Set(context, v8_str(isolate, "intercepted_named"),
4119 : named->NewInstance(context).ToLocalChecked())
4120 : .FromJust());
4121 :
4122 : // Create object with indexed interceptor.
4123 5 : v8::Local<v8::ObjectTemplate> indexed = v8::ObjectTemplate::New(isolate);
4124 : indexed->SetHandler(v8::IndexedPropertyHandlerConfiguration(
4125 5 : IndexedGetter, nullptr, nullptr, nullptr, IndexedEnum));
4126 25 : CHECK(env->Global()
4127 : ->Set(context, v8_str(isolate, "intercepted_indexed"),
4128 : indexed->NewInstance(context).ToLocalChecked())
4129 : .FromJust());
4130 :
4131 : // Create object with both named and indexed interceptor.
4132 5 : v8::Local<v8::ObjectTemplate> both = v8::ObjectTemplate::New(isolate);
4133 : both->SetHandler(v8::NamedPropertyHandlerConfiguration(
4134 5 : NamedGetter, nullptr, nullptr, nullptr, NamedEnum));
4135 : both->SetHandler(v8::IndexedPropertyHandlerConfiguration(
4136 5 : IndexedGetter, nullptr, nullptr, nullptr, IndexedEnum));
4137 25 : CHECK(env->Global()
4138 : ->Set(context, v8_str(isolate, "intercepted_both"),
4139 : both->NewInstance(context).ToLocalChecked())
4140 : .FromJust());
4141 :
4142 : // Get mirrors for the three objects with interceptor.
4143 : CompileRun(
4144 : "var named_mirror = debug.MakeMirror(intercepted_named);"
4145 : "var indexed_mirror = debug.MakeMirror(intercepted_indexed);"
4146 : "var both_mirror = debug.MakeMirror(intercepted_both)");
4147 10 : CHECK(CompileRun("named_mirror instanceof debug.ObjectMirror")
4148 : ->BooleanValue(context)
4149 : .FromJust());
4150 10 : CHECK(CompileRun("indexed_mirror instanceof debug.ObjectMirror")
4151 : ->BooleanValue(context)
4152 : .FromJust());
4153 10 : CHECK(CompileRun("both_mirror instanceof debug.ObjectMirror")
4154 : ->BooleanValue(context)
4155 : .FromJust());
4156 :
4157 : // Get the property names from the interceptors
4158 : CompileRun(
4159 : "named_names = named_mirror.propertyNames();"
4160 : "indexed_names = indexed_mirror.propertyNames();"
4161 : "both_names = both_mirror.propertyNames()");
4162 10 : CHECK_EQ(3, CompileRun("named_names.length")->Int32Value(context).FromJust());
4163 10 : CHECK_EQ(2,
4164 : CompileRun("indexed_names.length")->Int32Value(context).FromJust());
4165 10 : CHECK_EQ(5, CompileRun("both_names.length")->Int32Value(context).FromJust());
4166 :
4167 : // Check the expected number of properties.
4168 : const char* source;
4169 : source = "named_mirror.properties().length";
4170 10 : CHECK_EQ(3, CompileRun(source)->Int32Value(context).FromJust());
4171 :
4172 : source = "indexed_mirror.properties().length";
4173 10 : CHECK_EQ(2, CompileRun(source)->Int32Value(context).FromJust());
4174 :
4175 : source = "both_mirror.properties().length";
4176 10 : CHECK_EQ(5, CompileRun(source)->Int32Value(context).FromJust());
4177 :
4178 : // Get the interceptor properties for the object with only named interceptor.
4179 : CompileRun("var named_values = named_mirror.properties()");
4180 :
4181 : // Check that the properties are interceptor properties.
4182 20 : for (int i = 0; i < 3; i++) {
4183 : EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4184 : SNPrintF(buffer,
4185 15 : "named_values[%d] instanceof debug.PropertyMirror", i);
4186 45 : CHECK(CompileRun(buffer.start())->BooleanValue(context).FromJust());
4187 :
4188 15 : SNPrintF(buffer, "named_values[%d].isNative()", i);
4189 45 : CHECK(CompileRun(buffer.start())->BooleanValue(context).FromJust());
4190 : }
4191 :
4192 : // Get the interceptor properties for the object with only indexed
4193 : // interceptor.
4194 : CompileRun("var indexed_values = indexed_mirror.properties()");
4195 :
4196 : // Check that the properties are interceptor properties.
4197 15 : for (int i = 0; i < 2; i++) {
4198 : EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4199 : SNPrintF(buffer,
4200 10 : "indexed_values[%d] instanceof debug.PropertyMirror", i);
4201 30 : CHECK(CompileRun(buffer.start())->BooleanValue(context).FromJust());
4202 : }
4203 :
4204 : // Get the interceptor properties for the object with both types of
4205 : // interceptors.
4206 : CompileRun("var both_values = both_mirror.properties()");
4207 :
4208 : // Check that the properties are interceptor properties.
4209 30 : for (int i = 0; i < 5; i++) {
4210 : EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4211 25 : SNPrintF(buffer, "both_values[%d] instanceof debug.PropertyMirror", i);
4212 75 : CHECK(CompileRun(buffer.start())->BooleanValue(context).FromJust());
4213 : }
4214 :
4215 : // Check the property names.
4216 : source = "both_values[0].name() == '1'";
4217 10 : CHECK(CompileRun(source)->BooleanValue(context).FromJust());
4218 :
4219 : source = "both_values[1].name() == '10'";
4220 10 : CHECK(CompileRun(source)->BooleanValue(context).FromJust());
4221 :
4222 : source = "both_values[2].name() == 'a'";
4223 10 : CHECK(CompileRun(source)->BooleanValue(context).FromJust());
4224 :
4225 : source = "both_values[3].name() == 'b'";
4226 10 : CHECK(CompileRun(source)->BooleanValue(context).FromJust());
4227 :
4228 : source = "both_values[4].name() == 'c'";
4229 10 : CHECK(CompileRun(source)->BooleanValue(context).FromJust());
4230 5 : }
4231 :
4232 :
4233 23723 : TEST(HiddenPrototypePropertyMirror) {
4234 : // Create a V8 environment with debug access.
4235 5 : DebugLocalContext env;
4236 5 : v8::Isolate* isolate = env->GetIsolate();
4237 10 : v8::HandleScope scope(isolate);
4238 5 : env.ExposeDebug();
4239 :
4240 5 : v8::Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
4241 10 : t0->InstanceTemplate()->Set(v8_str(isolate, "x"),
4242 20 : v8::Number::New(isolate, 0));
4243 5 : v8::Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
4244 5 : t1->SetHiddenPrototype(true);
4245 10 : t1->InstanceTemplate()->Set(v8_str(isolate, "y"),
4246 20 : v8::Number::New(isolate, 1));
4247 5 : v8::Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
4248 5 : t2->SetHiddenPrototype(true);
4249 10 : t2->InstanceTemplate()->Set(v8_str(isolate, "z"),
4250 20 : v8::Number::New(isolate, 2));
4251 5 : v8::Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
4252 10 : t3->InstanceTemplate()->Set(v8_str(isolate, "u"),
4253 20 : v8::Number::New(isolate, 3));
4254 :
4255 : v8::Local<v8::Context> context = env.context();
4256 : // Create object and set them on the global object.
4257 : v8::Local<v8::Object> o0 = t0->GetFunction(context)
4258 5 : .ToLocalChecked()
4259 : ->NewInstance(context)
4260 : .ToLocalChecked();
4261 20 : CHECK(env->Global()->Set(context, v8_str(isolate, "o0"), o0).FromJust());
4262 : v8::Local<v8::Object> o1 = t1->GetFunction(context)
4263 5 : .ToLocalChecked()
4264 : ->NewInstance(context)
4265 : .ToLocalChecked();
4266 20 : CHECK(env->Global()->Set(context, v8_str(isolate, "o1"), o1).FromJust());
4267 : v8::Local<v8::Object> o2 = t2->GetFunction(context)
4268 5 : .ToLocalChecked()
4269 : ->NewInstance(context)
4270 : .ToLocalChecked();
4271 20 : CHECK(env->Global()->Set(context, v8_str(isolate, "o2"), o2).FromJust());
4272 : v8::Local<v8::Object> o3 = t3->GetFunction(context)
4273 5 : .ToLocalChecked()
4274 : ->NewInstance(context)
4275 : .ToLocalChecked();
4276 20 : CHECK(env->Global()->Set(context, v8_str(isolate, "o3"), o3).FromJust());
4277 :
4278 : // Get mirrors for the four objects.
4279 : CompileRun(
4280 : "var o0_mirror = debug.MakeMirror(o0);"
4281 : "var o1_mirror = debug.MakeMirror(o1);"
4282 : "var o2_mirror = debug.MakeMirror(o2);"
4283 : "var o3_mirror = debug.MakeMirror(o3)");
4284 10 : CHECK(CompileRun("o0_mirror instanceof debug.ObjectMirror")
4285 : ->BooleanValue(context)
4286 : .FromJust());
4287 10 : CHECK(CompileRun("o1_mirror instanceof debug.ObjectMirror")
4288 : ->BooleanValue(context)
4289 : .FromJust());
4290 10 : CHECK(CompileRun("o2_mirror instanceof debug.ObjectMirror")
4291 : ->BooleanValue(context)
4292 : .FromJust());
4293 10 : CHECK(CompileRun("o3_mirror instanceof debug.ObjectMirror")
4294 : ->BooleanValue(context)
4295 : .FromJust());
4296 :
4297 : // Check that each object has one property.
4298 10 : CHECK_EQ(1, CompileRun("o0_mirror.propertyNames().length")
4299 : ->Int32Value(context)
4300 : .FromJust());
4301 10 : CHECK_EQ(1, CompileRun("o1_mirror.propertyNames().length")
4302 : ->Int32Value(context)
4303 : .FromJust());
4304 10 : CHECK_EQ(1, CompileRun("o2_mirror.propertyNames().length")
4305 : ->Int32Value(context)
4306 : .FromJust());
4307 10 : CHECK_EQ(1, CompileRun("o3_mirror.propertyNames().length")
4308 : ->Int32Value(context)
4309 : .FromJust());
4310 :
4311 : // Set o1 as prototype for o0. o1 has the hidden prototype flag so all
4312 : // properties on o1 should be seen on o0.
4313 15 : CHECK(o0->Set(context, v8_str(isolate, "__proto__"), o1).FromJust());
4314 10 : CHECK_EQ(2, CompileRun("o0_mirror.propertyNames().length")
4315 : ->Int32Value(context)
4316 : .FromJust());
4317 10 : CHECK_EQ(0, CompileRun("o0_mirror.property('x').value().value()")
4318 : ->Int32Value(context)
4319 : .FromJust());
4320 10 : CHECK_EQ(1, CompileRun("o0_mirror.property('y').value().value()")
4321 : ->Int32Value(context)
4322 : .FromJust());
4323 :
4324 : // Set o2 as prototype for o0 (it will end up after o1 as o1 has the hidden
4325 : // prototype flag. o2 also has the hidden prototype flag so all properties
4326 : // on o2 should be seen on o0 as well as properties on o1.
4327 15 : CHECK(o0->Set(context, v8_str(isolate, "__proto__"), o2).FromJust());
4328 10 : CHECK_EQ(3, CompileRun("o0_mirror.propertyNames().length")
4329 : ->Int32Value(context)
4330 : .FromJust());
4331 10 : CHECK_EQ(0, CompileRun("o0_mirror.property('x').value().value()")
4332 : ->Int32Value(context)
4333 : .FromJust());
4334 10 : CHECK_EQ(1, CompileRun("o0_mirror.property('y').value().value()")
4335 : ->Int32Value(context)
4336 : .FromJust());
4337 10 : CHECK_EQ(2, CompileRun("o0_mirror.property('z').value().value()")
4338 : ->Int32Value(context)
4339 : .FromJust());
4340 :
4341 : // Set o3 as prototype for o0 (it will end up after o1 and o2 as both o1 and
4342 : // o2 has the hidden prototype flag. o3 does not have the hidden prototype
4343 : // flag so properties on o3 should not be seen on o0 whereas the properties
4344 : // from o1 and o2 should still be seen on o0.
4345 : // Final prototype chain: o0 -> o1 -> o2 -> o3
4346 : // Hidden prototypes: ^^ ^^
4347 15 : CHECK(o0->Set(context, v8_str(isolate, "__proto__"), o3).FromJust());
4348 10 : CHECK_EQ(3, CompileRun("o0_mirror.propertyNames().length")
4349 : ->Int32Value(context)
4350 : .FromJust());
4351 10 : CHECK_EQ(1, CompileRun("o3_mirror.propertyNames().length")
4352 : ->Int32Value(context)
4353 : .FromJust());
4354 10 : CHECK_EQ(0, CompileRun("o0_mirror.property('x').value().value()")
4355 : ->Int32Value(context)
4356 : .FromJust());
4357 10 : CHECK_EQ(1, CompileRun("o0_mirror.property('y').value().value()")
4358 : ->Int32Value(context)
4359 : .FromJust());
4360 10 : CHECK_EQ(2, CompileRun("o0_mirror.property('z').value().value()")
4361 : ->Int32Value(context)
4362 : .FromJust());
4363 10 : CHECK(CompileRun("o0_mirror.property('u').isUndefined()")
4364 : ->BooleanValue(context)
4365 : .FromJust());
4366 :
4367 : // The prototype (__proto__) for o0 should be o3 as o1 and o2 are hidden.
4368 10 : CHECK(CompileRun("o0_mirror.protoObject().value() == o3_mirror.value()")
4369 : ->BooleanValue(context)
4370 : .FromJust());
4371 5 : }
4372 :
4373 :
4374 15 : static void ProtperyXNativeGetter(
4375 : v8::Local<v8::String> property,
4376 : const v8::PropertyCallbackInfo<v8::Value>& info) {
4377 : info.GetReturnValue().Set(10);
4378 15 : }
4379 :
4380 :
4381 23723 : TEST(NativeGetterPropertyMirror) {
4382 : // Create a V8 environment with debug access.
4383 5 : DebugLocalContext env;
4384 5 : v8::Isolate* isolate = env->GetIsolate();
4385 10 : v8::HandleScope scope(isolate);
4386 5 : env.ExposeDebug();
4387 :
4388 5 : v8::Local<v8::Context> context = env.context();
4389 5 : v8::Local<v8::String> name = v8_str(isolate, "x");
4390 : // Create object with named accessor.
4391 5 : v8::Local<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
4392 : named->SetAccessor(name, &ProtperyXNativeGetter, nullptr,
4393 5 : v8::Local<v8::Value>(), v8::DEFAULT, v8::None);
4394 :
4395 : // Create object with named property getter.
4396 25 : CHECK(env->Global()
4397 : ->Set(context, v8_str(isolate, "instance"),
4398 : named->NewInstance(context).ToLocalChecked())
4399 : .FromJust());
4400 10 : CHECK_EQ(10, CompileRun("instance.x")->Int32Value(context).FromJust());
4401 :
4402 : // Get mirror for the object with property getter.
4403 : CompileRun("var instance_mirror = debug.MakeMirror(instance);");
4404 10 : CHECK(CompileRun("instance_mirror instanceof debug.ObjectMirror")
4405 : ->BooleanValue(context)
4406 : .FromJust());
4407 :
4408 : CompileRun("var named_names = instance_mirror.propertyNames();");
4409 10 : CHECK_EQ(1, CompileRun("named_names.length")->Int32Value(context).FromJust());
4410 10 : CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue(context).FromJust());
4411 10 : CHECK(CompileRun("instance_mirror.property('x').value().isNumber()")
4412 : ->BooleanValue(context)
4413 : .FromJust());
4414 10 : CHECK(CompileRun("instance_mirror.property('x').value().value() == 10")
4415 : ->BooleanValue(context)
4416 : .FromJust());
4417 5 : }
4418 :
4419 :
4420 10 : static void ProtperyXNativeGetterThrowingError(
4421 : v8::Local<v8::String> property,
4422 : const v8::PropertyCallbackInfo<v8::Value>& info) {
4423 : CompileRun("throw new Error('Error message');");
4424 10 : }
4425 :
4426 :
4427 23723 : TEST(NativeGetterThrowingErrorPropertyMirror) {
4428 : // Create a V8 environment with debug access.
4429 5 : DebugLocalContext env;
4430 5 : v8::Isolate* isolate = env->GetIsolate();
4431 10 : v8::HandleScope scope(isolate);
4432 5 : env.ExposeDebug();
4433 :
4434 5 : v8::Local<v8::Context> context = env.context();
4435 5 : v8::Local<v8::String> name = v8_str(isolate, "x");
4436 : // Create object with named accessor.
4437 5 : v8::Local<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
4438 : named->SetAccessor(name, &ProtperyXNativeGetterThrowingError, nullptr,
4439 5 : v8::Local<v8::Value>(), v8::DEFAULT, v8::None);
4440 :
4441 : // Create object with named property getter.
4442 25 : CHECK(env->Global()
4443 : ->Set(context, v8_str(isolate, "instance"),
4444 : named->NewInstance(context).ToLocalChecked())
4445 : .FromJust());
4446 :
4447 : // Get mirror for the object with property getter.
4448 : CompileRun("var instance_mirror = debug.MakeMirror(instance);");
4449 10 : CHECK(CompileRun("instance_mirror instanceof debug.ObjectMirror")
4450 : ->BooleanValue(context)
4451 : .FromJust());
4452 : CompileRun("named_names = instance_mirror.propertyNames();");
4453 10 : CHECK_EQ(1, CompileRun("named_names.length")->Int32Value(context).FromJust());
4454 10 : CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue(context).FromJust());
4455 10 : CHECK(CompileRun("instance_mirror.property('x').value().isError()")
4456 : ->BooleanValue(context)
4457 : .FromJust());
4458 :
4459 : // Check that the message is that passed to the Error constructor.
4460 10 : CHECK(
4461 : CompileRun(
4462 : "instance_mirror.property('x').value().message() == 'Error message'")
4463 : ->BooleanValue(context)
4464 : .FromJust());
4465 5 : }
4466 :
4467 :
4468 : // Test that hidden properties object is not returned as an unnamed property
4469 : // among regular properties.
4470 : // See http://crbug.com/26491
4471 23723 : TEST(NoHiddenProperties) {
4472 : // Create a V8 environment with debug access.
4473 5 : DebugLocalContext env;
4474 5 : v8::Isolate* isolate = env->GetIsolate();
4475 10 : v8::HandleScope scope(isolate);
4476 5 : env.ExposeDebug();
4477 :
4478 : v8::Local<v8::Context> context = env.context();
4479 : // Create an object in the global scope.
4480 : const char* source = "var obj = {a: 1};";
4481 5 : v8::Script::Compile(context, v8_str(isolate, source))
4482 5 : .ToLocalChecked()
4483 : ->Run(context)
4484 5 : .ToLocalChecked();
4485 : v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
4486 20 : env->Global()->Get(context, v8_str(isolate, "obj")).ToLocalChecked());
4487 : // Set a hidden property on the object.
4488 : obj->SetPrivate(
4489 : env.context(),
4490 : v8::Private::New(isolate, v8_str(isolate, "v8::test-debug::a")),
4491 15 : v8::Int32::New(isolate, 11))
4492 10 : .FromJust();
4493 :
4494 : // Get mirror for the object with property getter.
4495 : CompileRun("var obj_mirror = debug.MakeMirror(obj);");
4496 10 : CHECK(CompileRun("obj_mirror instanceof debug.ObjectMirror")
4497 : ->BooleanValue(context)
4498 : .FromJust());
4499 : CompileRun("var named_names = obj_mirror.propertyNames();");
4500 : // There should be exactly one property. But there is also an unnamed
4501 : // property whose value is hidden properties dictionary. The latter
4502 : // property should not be in the list of reguar properties.
4503 10 : CHECK_EQ(1, CompileRun("named_names.length")->Int32Value(context).FromJust());
4504 10 : CHECK(CompileRun("named_names[0] == 'a'")->BooleanValue(context).FromJust());
4505 10 : CHECK(CompileRun("obj_mirror.property('a').value().value() == 1")
4506 : ->BooleanValue(context)
4507 : .FromJust());
4508 :
4509 : // Object created by t0 will become hidden prototype of object 'obj'.
4510 5 : v8::Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
4511 10 : t0->InstanceTemplate()->Set(v8_str(isolate, "b"),
4512 20 : v8::Number::New(isolate, 2));
4513 5 : t0->SetHiddenPrototype(true);
4514 5 : v8::Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
4515 10 : t1->InstanceTemplate()->Set(v8_str(isolate, "c"),
4516 20 : v8::Number::New(isolate, 3));
4517 :
4518 : // Create proto objects, add hidden properties to them and set them on
4519 : // the global object.
4520 : v8::Local<v8::Object> protoObj = t0->GetFunction(context)
4521 5 : .ToLocalChecked()
4522 : ->NewInstance(context)
4523 : .ToLocalChecked();
4524 : protoObj->SetPrivate(
4525 : env.context(),
4526 : v8::Private::New(isolate, v8_str(isolate, "v8::test-debug::b")),
4527 15 : v8::Int32::New(isolate, 12))
4528 10 : .FromJust();
4529 20 : CHECK(env->Global()
4530 : ->Set(context, v8_str(isolate, "protoObj"), protoObj)
4531 : .FromJust());
4532 : v8::Local<v8::Object> grandProtoObj = t1->GetFunction(context)
4533 5 : .ToLocalChecked()
4534 : ->NewInstance(context)
4535 : .ToLocalChecked();
4536 : grandProtoObj->SetPrivate(env.context(),
4537 : v8::Private::New(
4538 : isolate, v8_str(isolate, "v8::test-debug::c")),
4539 15 : v8::Int32::New(isolate, 13))
4540 10 : .FromJust();
4541 20 : CHECK(env->Global()
4542 : ->Set(context, v8_str(isolate, "grandProtoObj"), grandProtoObj)
4543 : .FromJust());
4544 :
4545 : // Setting prototypes: obj->protoObj->grandProtoObj
4546 15 : CHECK(protoObj->Set(context, v8_str(isolate, "__proto__"), grandProtoObj)
4547 : .FromJust());
4548 15 : CHECK(obj->Set(context, v8_str(isolate, "__proto__"), protoObj).FromJust());
4549 :
4550 : // Get mirror for the object with property getter.
4551 : CompileRun("var obj_mirror = debug.MakeMirror(obj);");
4552 10 : CHECK(CompileRun("obj_mirror instanceof debug.ObjectMirror")
4553 : ->BooleanValue(context)
4554 : .FromJust());
4555 : CompileRun("var named_names = obj_mirror.propertyNames();");
4556 : // There should be exactly two properties - one from the object itself and
4557 : // another from its hidden prototype.
4558 10 : CHECK_EQ(2, CompileRun("named_names.length")->Int32Value(context).FromJust());
4559 10 : CHECK(CompileRun("named_names.sort(); named_names[0] == 'a' &&"
4560 : "named_names[1] == 'b'")
4561 : ->BooleanValue(context)
4562 : .FromJust());
4563 10 : CHECK(CompileRun("obj_mirror.property('a').value().value() == 1")
4564 : ->BooleanValue(context)
4565 : .FromJust());
4566 10 : CHECK(CompileRun("obj_mirror.property('b').value().value() == 2")
4567 : ->BooleanValue(context)
4568 : .FromJust());
4569 5 : }
4570 :
4571 :
4572 23723 : TEST(SetDebugEventListenerOnUninitializedVM) {
4573 5 : EnableDebugger(CcTest::isolate());
4574 5 : }
4575 :
4576 : // Source for a JavaScript function which returns the data parameter of a
4577 : // function called in the context of the debugger. If no data parameter is
4578 : // passed it throws an exception.
4579 : static const char* debugger_call_with_data_source =
4580 : "function debugger_call_with_data(exec_state, data) {"
4581 : " if (data) return data;"
4582 : " throw 'No data!'"
4583 : "}";
4584 : v8::Local<v8::Function> debugger_call_with_data;
4585 :
4586 :
4587 : // Source for a JavaScript function which returns the data parameter of a
4588 : // function called in the context of the debugger. If no data parameter is
4589 : // passed it throws an exception.
4590 : static const char* debugger_call_with_closure_source =
4591 : "var x = 3;"
4592 : "(function (exec_state) {"
4593 : " if (exec_state.y) return x - 1;"
4594 : " exec_state.y = x;"
4595 : " return exec_state.y"
4596 : "})";
4597 : v8::Local<v8::Function> debugger_call_with_closure;
4598 :
4599 : // Function to retrieve the number of JavaScript frames by calling a JavaScript
4600 : // in the debugger.
4601 10 : static void CheckFrameCount(const v8::FunctionCallbackInfo<v8::Value>& args) {
4602 10 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
4603 20 : CHECK(v8::debug::Call(context, frame_count).ToLocalChecked()->IsNumber());
4604 40 : CHECK_EQ(args[0]->Int32Value(context).FromJust(),
4605 : v8::debug::Call(context, frame_count)
4606 : .ToLocalChecked()
4607 : ->Int32Value(context)
4608 : .FromJust());
4609 10 : }
4610 :
4611 :
4612 : // Function to retrieve the source line of the top JavaScript frame by calling a
4613 : // JavaScript function in the debugger.
4614 40 : static void CheckSourceLine(const v8::FunctionCallbackInfo<v8::Value>& args) {
4615 40 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
4616 80 : CHECK(
4617 : v8::debug::Call(context, frame_source_line).ToLocalChecked()->IsNumber());
4618 160 : CHECK_EQ(args[0]->Int32Value(context).FromJust(),
4619 : v8::debug::Call(context, frame_source_line)
4620 : .ToLocalChecked()
4621 : ->Int32Value(context)
4622 : .FromJust());
4623 40 : }
4624 :
4625 :
4626 : // Function to test passing an additional parameter to a JavaScript function
4627 : // called in the debugger. It also tests that functions called in the debugger
4628 : // can throw exceptions.
4629 5 : static void CheckDataParameter(
4630 25 : const v8::FunctionCallbackInfo<v8::Value>& args) {
4631 5 : v8::Local<v8::String> data = v8_str(args.GetIsolate(), "Test");
4632 5 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
4633 10 : CHECK(v8::debug::Call(context, debugger_call_with_data, data)
4634 : .ToLocalChecked()
4635 : ->IsString());
4636 :
4637 15 : for (int i = 0; i < 3; i++) {
4638 15 : v8::TryCatch catcher(args.GetIsolate());
4639 30 : CHECK(v8::debug::Call(context, debugger_call_with_data).IsEmpty());
4640 15 : CHECK(catcher.HasCaught());
4641 30 : CHECK(catcher.Exception()->IsString());
4642 15 : }
4643 5 : }
4644 :
4645 :
4646 : // Function to test using a JavaScript with closure in the debugger.
4647 5 : static void CheckClosure(const v8::FunctionCallbackInfo<v8::Value>& args) {
4648 5 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
4649 10 : CHECK(v8::debug::Call(context, debugger_call_with_closure)
4650 : .ToLocalChecked()
4651 : ->IsNumber());
4652 15 : CHECK_EQ(3, v8::debug::Call(context, debugger_call_with_closure)
4653 : .ToLocalChecked()
4654 : ->Int32Value(context)
4655 : .FromJust());
4656 5 : }
4657 :
4658 :
4659 : // Test functions called through the debugger.
4660 23723 : TEST(CallFunctionInDebugger) {
4661 : // Create and enter a context with the functions CheckFrameCount,
4662 : // CheckSourceLine and CheckDataParameter installed.
4663 5 : v8::Isolate* isolate = CcTest::isolate();
4664 5 : v8::HandleScope scope(isolate);
4665 : v8::Local<v8::ObjectTemplate> global_template =
4666 5 : v8::ObjectTemplate::New(isolate);
4667 : global_template->Set(v8_str(isolate, "CheckFrameCount"),
4668 15 : v8::FunctionTemplate::New(isolate, CheckFrameCount));
4669 : global_template->Set(v8_str(isolate, "CheckSourceLine"),
4670 15 : v8::FunctionTemplate::New(isolate, CheckSourceLine));
4671 : global_template->Set(v8_str(isolate, "CheckDataParameter"),
4672 15 : v8::FunctionTemplate::New(isolate, CheckDataParameter));
4673 : global_template->Set(v8_str(isolate, "CheckClosure"),
4674 15 : v8::FunctionTemplate::New(isolate, CheckClosure));
4675 : v8::Local<v8::Context> context =
4676 5 : v8::Context::New(isolate, nullptr, global_template);
4677 : v8::Context::Scope context_scope(context);
4678 :
4679 : // Compile a function for checking the number of JavaScript frames.
4680 5 : v8::Script::Compile(context, v8_str(isolate, frame_count_source))
4681 5 : .ToLocalChecked()
4682 : ->Run(context)
4683 5 : .ToLocalChecked();
4684 : frame_count = v8::Local<v8::Function>::Cast(
4685 : context->Global()
4686 15 : ->Get(context, v8_str(isolate, "frame_count"))
4687 10 : .ToLocalChecked());
4688 :
4689 : // Compile a function for returning the source line for the top frame.
4690 5 : v8::Script::Compile(context, v8_str(isolate, frame_source_line_source))
4691 5 : .ToLocalChecked()
4692 : ->Run(context)
4693 5 : .ToLocalChecked();
4694 : frame_source_line = v8::Local<v8::Function>::Cast(
4695 : context->Global()
4696 15 : ->Get(context, v8_str(isolate, "frame_source_line"))
4697 10 : .ToLocalChecked());
4698 :
4699 : // Compile a function returning the data parameter.
4700 5 : v8::Script::Compile(context, v8_str(isolate, debugger_call_with_data_source))
4701 5 : .ToLocalChecked()
4702 : ->Run(context)
4703 5 : .ToLocalChecked();
4704 : debugger_call_with_data = v8::Local<v8::Function>::Cast(
4705 : context->Global()
4706 15 : ->Get(context, v8_str(isolate, "debugger_call_with_data"))
4707 10 : .ToLocalChecked());
4708 :
4709 : // Compile a function capturing closure.
4710 : debugger_call_with_closure = v8::Local<v8::Function>::Cast(
4711 : v8::Script::Compile(context,
4712 5 : v8_str(isolate, debugger_call_with_closure_source))
4713 5 : .ToLocalChecked()
4714 : ->Run(context)
4715 10 : .ToLocalChecked());
4716 :
4717 : // Calling a function through the debugger returns 0 frames if there are
4718 : // no JavaScript frames.
4719 20 : CHECK(v8::Integer::New(isolate, 0)
4720 : ->Equals(context,
4721 : v8::debug::Call(context, frame_count).ToLocalChecked())
4722 : .FromJust());
4723 :
4724 : // Test that the number of frames can be retrieved.
4725 5 : v8::Script::Compile(context, v8_str(isolate, "CheckFrameCount(1)"))
4726 5 : .ToLocalChecked()
4727 : ->Run(context)
4728 5 : .ToLocalChecked();
4729 : v8::Script::Compile(context, v8_str(isolate,
4730 : "function f() {"
4731 : " CheckFrameCount(2);"
4732 5 : "}; f()"))
4733 5 : .ToLocalChecked()
4734 : ->Run(context)
4735 5 : .ToLocalChecked();
4736 :
4737 : // Test that the source line can be retrieved.
4738 5 : v8::Script::Compile(context, v8_str(isolate, "CheckSourceLine(0)"))
4739 5 : .ToLocalChecked()
4740 : ->Run(context)
4741 5 : .ToLocalChecked();
4742 : v8::Script::Compile(context, v8_str(isolate,
4743 : "function f() {\n"
4744 : " CheckSourceLine(1)\n"
4745 : " CheckSourceLine(2)\n"
4746 : " CheckSourceLine(3)\n"
4747 5 : "}; f()"))
4748 5 : .ToLocalChecked()
4749 : ->Run(context)
4750 5 : .ToLocalChecked();
4751 :
4752 : // Test that a parameter can be passed to a function called in the debugger.
4753 5 : v8::Script::Compile(context, v8_str(isolate, "CheckDataParameter()"))
4754 5 : .ToLocalChecked()
4755 : ->Run(context)
4756 5 : .ToLocalChecked();
4757 :
4758 : // Test that a function with closure can be run in the debugger.
4759 5 : v8::Script::Compile(context, v8_str(isolate, "CheckClosure()"))
4760 5 : .ToLocalChecked()
4761 : ->Run(context)
4762 5 : .ToLocalChecked();
4763 :
4764 : // Test that the source line is correct when there is a line offset.
4765 : v8::ScriptOrigin origin(v8_str(isolate, "test"),
4766 5 : v8::Integer::New(isolate, 7));
4767 5 : v8::Script::Compile(context, v8_str(isolate, "CheckSourceLine(7)"), &origin)
4768 5 : .ToLocalChecked()
4769 : ->Run(context)
4770 5 : .ToLocalChecked();
4771 : v8::Script::Compile(context, v8_str(isolate,
4772 : "function f() {\n"
4773 : " CheckSourceLine(8)\n"
4774 : " CheckSourceLine(9)\n"
4775 : " CheckSourceLine(10)\n"
4776 : "}; f()"),
4777 5 : &origin)
4778 5 : .ToLocalChecked()
4779 : ->Run(context)
4780 10 : .ToLocalChecked();
4781 5 : }
4782 :
4783 :
4784 : // Test that clearing the debug event listener actually clears all break points
4785 : // and related information.
4786 23723 : TEST(DebuggerUnload) {
4787 5 : DebugLocalContext env;
4788 :
4789 : // Check debugger is unloaded before it is used.
4790 : CheckDebuggerUnloaded();
4791 :
4792 : // Set a debug event listener.
4793 5 : break_point_hit_count = 0;
4794 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
4795 5 : v8::Local<v8::Context> context = env.context();
4796 : {
4797 5 : v8::HandleScope scope(env->GetIsolate());
4798 : // Create a couple of functions for the test.
4799 : v8::Local<v8::Function> foo =
4800 5 : CompileFunction(&env, "function foo(){x=1}", "foo");
4801 : v8::Local<v8::Function> bar =
4802 5 : CompileFunction(&env, "function bar(){y=2}", "bar");
4803 :
4804 : // Set some break points.
4805 5 : SetBreakPoint(foo, 0);
4806 5 : SetBreakPoint(foo, 4);
4807 5 : SetBreakPoint(bar, 0);
4808 5 : SetBreakPoint(bar, 4);
4809 :
4810 : // Make sure that the break points are there.
4811 5 : break_point_hit_count = 0;
4812 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
4813 5 : CHECK_EQ(2, break_point_hit_count);
4814 15 : bar->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
4815 5 : CHECK_EQ(4, break_point_hit_count);
4816 : }
4817 :
4818 : // Remove the debug event listener without clearing breakpoints. Do this
4819 : // outside a handle scope.
4820 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
4821 : CheckDebuggerUnloaded();
4822 5 : }
4823 :
4824 : int event_listener_hit_count = 0;
4825 :
4826 : // Debugger event listener which clears itself while active.
4827 5 : static void EventListenerClearingItself(
4828 : const v8::Debug::EventDetails& details) {
4829 5 : event_listener_hit_count++;
4830 :
4831 : // Clear debug event listener.
4832 5 : SetDebugEventListener(details.GetIsolate(), nullptr);
4833 5 : }
4834 :
4835 :
4836 : // Test clearing the debug message handler while processing a debug event.
4837 23723 : TEST(DebuggerClearEventListenerWhileActive) {
4838 5 : DebugLocalContext env;
4839 10 : v8::HandleScope scope(env->GetIsolate());
4840 :
4841 : // Check debugger is unloaded before it is used.
4842 : CheckDebuggerUnloaded();
4843 :
4844 : // Set a debug event listener.
4845 5 : SetDebugEventListener(env->GetIsolate(), EventListenerClearingItself);
4846 :
4847 : // Run code to throw an uncaught exception. This should trigger the listener.
4848 : CompileRun("throw 1");
4849 :
4850 : // The event listener should have been called.
4851 5 : CHECK_EQ(1, event_listener_hit_count);
4852 :
4853 : CheckDebuggerUnloaded();
4854 5 : }
4855 :
4856 : // Test for issue http://code.google.com/p/v8/issues/detail?id=289.
4857 : // Make sure that DebugGetLoadedScripts doesn't return scripts
4858 : // with disposed external source.
4859 : class EmptyExternalStringResource : public v8::String::ExternalStringResource {
4860 : public:
4861 : EmptyExternalStringResource() { empty_[0] = 0; }
4862 0 : virtual ~EmptyExternalStringResource() {}
4863 0 : virtual size_t length() const { return empty_.length(); }
4864 0 : virtual const uint16_t* data() const { return empty_.start(); }
4865 : private:
4866 : ::v8::internal::EmbeddedVector<uint16_t, 1> empty_;
4867 : };
4868 :
4869 23723 : TEST(DebugScriptLineEndsAreAscending) {
4870 5 : DebugLocalContext env;
4871 5 : v8::Isolate* isolate = env->GetIsolate();
4872 10 : v8::HandleScope scope(isolate);
4873 5 : env.ExposeDebug();
4874 :
4875 : // Compile a test script.
4876 : v8::Local<v8::String> script = v8_str(isolate,
4877 : "function f() {\n"
4878 : " debugger;\n"
4879 5 : "}\n");
4880 :
4881 5 : v8::ScriptOrigin origin1 = v8::ScriptOrigin(v8_str(isolate, "name"));
4882 : v8::Local<v8::Script> script1 =
4883 5 : v8::Script::Compile(env.context(), script, &origin1).ToLocalChecked();
4884 : USE(script1);
4885 :
4886 : Handle<v8::internal::FixedArray> instances;
4887 : {
4888 5 : v8::internal::Debug* debug = CcTest::i_isolate()->debug();
4889 5 : v8::internal::DebugScope debug_scope(debug);
4890 5 : CHECK(!debug_scope.failed());
4891 5 : instances = debug->GetLoadedScripts();
4892 : }
4893 :
4894 5 : CHECK_GT(instances->length(), 0);
4895 165 : for (int i = 0; i < instances->length(); i++) {
4896 : Handle<v8::internal::Script> script = Handle<v8::internal::Script>(
4897 : v8::internal::Script::cast(instances->get(i)));
4898 :
4899 80 : v8::internal::Script::InitLineEnds(script);
4900 : v8::internal::FixedArray* ends =
4901 : v8::internal::FixedArray::cast(script->line_ends());
4902 80 : CHECK_GT(ends->length(), 0);
4903 :
4904 : int prev_end = -1;
4905 67140 : for (int j = 0; j < ends->length(); j++) {
4906 : const int curr_end = v8::internal::Smi::ToInt(ends->get(j));
4907 33530 : CHECK_GT(curr_end, prev_end);
4908 : prev_end = curr_end;
4909 : }
4910 : }
4911 5 : }
4912 :
4913 :
4914 : // Test script break points set on lines.
4915 23723 : TEST(ScriptNameAndData) {
4916 5 : DebugLocalContext env;
4917 10 : v8::HandleScope scope(env->GetIsolate());
4918 5 : env.ExposeDebug();
4919 :
4920 : // Create functions for retrieving script name and data for the function on
4921 : // the top frame when hitting a break point.
4922 : frame_script_name = CompileFunction(&env,
4923 : frame_script_name_source,
4924 5 : "frame_script_name");
4925 :
4926 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
4927 :
4928 5 : v8::Local<v8::Context> context = env.context();
4929 : // Test function source.
4930 : v8::Local<v8::String> script = v8_str(env->GetIsolate(),
4931 : "function f() {\n"
4932 : " debugger;\n"
4933 5 : "}\n");
4934 :
4935 : v8::ScriptOrigin origin1 =
4936 5 : v8::ScriptOrigin(v8_str(env->GetIsolate(), "name"));
4937 : v8::Local<v8::Script> script1 =
4938 5 : v8::Script::Compile(context, script, &origin1).ToLocalChecked();
4939 5 : script1->Run(context).ToLocalChecked();
4940 : v8::Local<v8::Function> f;
4941 : f = v8::Local<v8::Function>::Cast(
4942 : env->Global()
4943 15 : ->Get(context, v8_str(env->GetIsolate(), "f"))
4944 5 : .ToLocalChecked());
4945 :
4946 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
4947 5 : CHECK_EQ(1, break_point_hit_count);
4948 5 : CHECK_EQ(0, strcmp("name", last_script_name_hit));
4949 :
4950 : // Compile the same script again without setting data. As the compilation
4951 : // cache is disabled when debugging expect the data to be missing.
4952 : v8::Script::Compile(context, script, &origin1)
4953 5 : .ToLocalChecked()
4954 : ->Run(context)
4955 5 : .ToLocalChecked();
4956 : f = v8::Local<v8::Function>::Cast(
4957 : env->Global()
4958 15 : ->Get(context, v8_str(env->GetIsolate(), "f"))
4959 5 : .ToLocalChecked());
4960 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
4961 5 : CHECK_EQ(2, break_point_hit_count);
4962 5 : CHECK_EQ(0, strcmp("name", last_script_name_hit));
4963 :
4964 : v8::Local<v8::String> data_obj_source =
4965 : v8_str(env->GetIsolate(),
4966 : "({ a: 'abc',\n"
4967 : " b: 123,\n"
4968 : " toString: function() { return this.a + ' ' + this.b; }\n"
4969 5 : "})\n");
4970 : v8::Script::Compile(context, data_obj_source)
4971 5 : .ToLocalChecked()
4972 : ->Run(context)
4973 5 : .ToLocalChecked();
4974 : v8::ScriptOrigin origin2 =
4975 5 : v8::ScriptOrigin(v8_str(env->GetIsolate(), "new name"));
4976 : v8::Local<v8::Script> script2 =
4977 5 : v8::Script::Compile(context, script, &origin2).ToLocalChecked();
4978 5 : script2->Run(context).ToLocalChecked();
4979 : f = v8::Local<v8::Function>::Cast(
4980 : env->Global()
4981 15 : ->Get(context, v8_str(env->GetIsolate(), "f"))
4982 5 : .ToLocalChecked());
4983 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
4984 5 : CHECK_EQ(3, break_point_hit_count);
4985 5 : CHECK_EQ(0, strcmp("new name", last_script_name_hit));
4986 :
4987 : v8::Local<v8::Script> script3 =
4988 5 : v8::Script::Compile(context, script, &origin2).ToLocalChecked();
4989 5 : script3->Run(context).ToLocalChecked();
4990 : f = v8::Local<v8::Function>::Cast(
4991 : env->Global()
4992 15 : ->Get(context, v8_str(env->GetIsolate(), "f"))
4993 5 : .ToLocalChecked());
4994 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
4995 5 : CHECK_EQ(4, break_point_hit_count);
4996 5 : }
4997 :
4998 :
4999 : static v8::Local<v8::Context> expected_context;
5000 : static v8::Local<v8::Value> expected_context_data;
5001 :
5002 :
5003 : // Check that the expected context is the one generating the debug event.
5004 35 : static void ContextCheckEventListener(
5005 : const v8::Debug::EventDetails& event_details) {
5006 70 : CHECK(event_details.GetEventContext() == expected_context);
5007 70 : CHECK(event_details.GetEventContext()->GetEmbedderData(0)->StrictEquals(
5008 : expected_context_data));
5009 35 : event_listener_hit_count++;
5010 35 : }
5011 :
5012 :
5013 : // Test which creates two contexts and sets different embedder data on each.
5014 : // Checks that this data is set correctly and that when the debug event
5015 : // listener is called the expected context is the one active.
5016 23723 : TEST(ContextData) {
5017 5 : v8::Isolate* isolate = CcTest::isolate();
5018 5 : v8::HandleScope scope(isolate);
5019 :
5020 : // Create two contexts.
5021 : v8::Local<v8::Context> context_1;
5022 : v8::Local<v8::Context> context_2;
5023 : v8::Local<v8::ObjectTemplate> global_template =
5024 : v8::Local<v8::ObjectTemplate>();
5025 : v8::Local<v8::Value> global_object = v8::Local<v8::Value>();
5026 : context_1 =
5027 5 : v8::Context::New(isolate, nullptr, global_template, global_object);
5028 : context_2 =
5029 5 : v8::Context::New(isolate, nullptr, global_template, global_object);
5030 :
5031 5 : SetDebugEventListener(isolate, ContextCheckEventListener);
5032 :
5033 : // Default data value is undefined.
5034 5 : CHECK(context_1->GetEmbedderData(0)->IsUndefined());
5035 5 : CHECK(context_2->GetEmbedderData(0)->IsUndefined());
5036 :
5037 : // Set and check different data values.
5038 5 : v8::Local<v8::String> data_1 = v8_str(isolate, "1");
5039 5 : v8::Local<v8::String> data_2 = v8_str(isolate, "2");
5040 5 : context_1->SetEmbedderData(0, data_1);
5041 5 : context_2->SetEmbedderData(0, data_2);
5042 5 : CHECK(context_1->GetEmbedderData(0)->StrictEquals(data_1));
5043 5 : CHECK(context_2->GetEmbedderData(0)->StrictEquals(data_2));
5044 :
5045 : // Simple test function which causes a break.
5046 : const char* source = "function f() { debugger; }";
5047 :
5048 : // Enter and run function in the first context.
5049 : {
5050 : v8::Context::Scope context_scope(context_1);
5051 5 : expected_context = context_1;
5052 5 : expected_context_data = data_1;
5053 5 : v8::Local<v8::Function> f = CompileFunction(isolate, source, "f");
5054 15 : f->Call(context_1, context_1->Global(), 0, nullptr).ToLocalChecked();
5055 : }
5056 :
5057 :
5058 : // Enter and run function in the second context.
5059 : {
5060 : v8::Context::Scope context_scope(context_2);
5061 5 : expected_context = context_2;
5062 5 : expected_context_data = data_2;
5063 5 : v8::Local<v8::Function> f = CompileFunction(isolate, source, "f");
5064 15 : f->Call(context_2, context_2->Global(), 0, nullptr).ToLocalChecked();
5065 : }
5066 :
5067 : // Two times compile event and two times break event.
5068 5 : CHECK_GT(event_listener_hit_count, 3);
5069 :
5070 5 : SetDebugEventListener(isolate, nullptr);
5071 5 : CheckDebuggerUnloaded();
5072 5 : }
5073 :
5074 : // Debug event listener which issues a debug break when it hits a break event.
5075 : static int event_listener_break_hit_count = 0;
5076 15 : static void DebugBreakEventListener(const v8::Debug::EventDetails& details) {
5077 : // Schedule a debug break for break events.
5078 15 : if (details.GetEvent() == v8::Break) {
5079 10 : event_listener_break_hit_count++;
5080 10 : if (event_listener_break_hit_count == 1) {
5081 5 : v8::debug::DebugBreak(details.GetIsolate());
5082 : }
5083 : }
5084 15 : }
5085 :
5086 : // Test that a debug break can be scheduled while in a event listener.
5087 23723 : TEST(DebugBreakInEventListener) {
5088 5 : i::FLAG_turbo_inlining = false; // Make sure g is not inlined into f.
5089 5 : DebugLocalContext env;
5090 10 : v8::HandleScope scope(env->GetIsolate());
5091 :
5092 5 : SetDebugEventListener(env->GetIsolate(), DebugBreakEventListener);
5093 :
5094 5 : v8::Local<v8::Context> context = env.context();
5095 : // Test functions.
5096 : const char* script = "function f() { debugger; g(); } function g() { }";
5097 : CompileRun(script);
5098 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
5099 : env->Global()
5100 15 : ->Get(context, v8_str(env->GetIsolate(), "f"))
5101 5 : .ToLocalChecked());
5102 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
5103 : env->Global()
5104 15 : ->Get(context, v8_str(env->GetIsolate(), "g"))
5105 5 : .ToLocalChecked());
5106 :
5107 : // Call f then g. The debugger statement in f will cause a break which will
5108 : // cause another break.
5109 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
5110 5 : CHECK_EQ(2, event_listener_break_hit_count);
5111 : // Calling g will not cause any additional breaks.
5112 15 : g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
5113 5 : CHECK_EQ(2, event_listener_break_hit_count);
5114 5 : }
5115 :
5116 :
5117 : #ifndef V8_INTERPRETED_REGEXP
5118 : // Debug event handler which gets the function on the top frame and schedules a
5119 : // break a number of times.
5120 5 : static void DebugEventDebugBreak(
5121 : const v8::Debug::EventDetails& event_details) {
5122 5 : v8::DebugEvent event = event_details.GetEvent();
5123 5 : v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
5124 5 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
5125 5 : if (event == v8::Break) {
5126 5 : break_point_hit_count++;
5127 :
5128 : // Get the name of the top frame function.
5129 5 : if (!frame_function_name.IsEmpty()) {
5130 : // Get the name of the function.
5131 : const int argc = 2;
5132 : v8::Local<v8::Value> argv[argc] = {
5133 5 : exec_state, v8::Integer::New(CcTest::isolate(), 0)};
5134 : v8::Local<v8::Value> result =
5135 5 : frame_function_name->Call(context, exec_state, argc, argv)
5136 5 : .ToLocalChecked();
5137 5 : if (result->IsUndefined()) {
5138 0 : last_function_hit[0] = '\0';
5139 : } else {
5140 5 : CHECK(result->IsString());
5141 : v8::Local<v8::String> function_name(
5142 5 : result->ToString(context).ToLocalChecked());
5143 5 : function_name->WriteUtf8(last_function_hit);
5144 : }
5145 : }
5146 :
5147 : // Keep forcing breaks.
5148 5 : if (break_point_hit_count < 20) {
5149 5 : v8::debug::DebugBreak(CcTest::isolate());
5150 : }
5151 : }
5152 5 : }
5153 :
5154 :
5155 23723 : TEST(RegExpDebugBreak) {
5156 : // This test only applies to native regexps.
5157 5 : DebugLocalContext env;
5158 10 : v8::HandleScope scope(env->GetIsolate());
5159 5 : v8::Local<v8::Context> context = env.context();
5160 : // Create a function for checking the function when hitting a break point.
5161 : frame_function_name = CompileFunction(&env,
5162 : frame_function_name_source,
5163 5 : "frame_function_name");
5164 :
5165 : // Test RegExp which matches white spaces and comments at the beginning of a
5166 : // source line.
5167 : const char* script =
5168 : "var sourceLineBeginningSkip = /^(?:[ \\v\\h]*(?:\\/\\*.*?\\*\\/)*)*/;\n"
5169 : "function f(s) { return s.match(sourceLineBeginningSkip)[0].length; }";
5170 :
5171 5 : v8::Local<v8::Function> f = CompileFunction(env->GetIsolate(), script, "f");
5172 : const int argc = 1;
5173 : v8::Local<v8::Value> argv[argc] = {
5174 5 : v8_str(env->GetIsolate(), " /* xxx */ a=0;")};
5175 : v8::Local<v8::Value> result =
5176 15 : f->Call(context, env->Global(), argc, argv).ToLocalChecked();
5177 10 : CHECK_EQ(12, result->Int32Value(context).FromJust());
5178 :
5179 5 : SetDebugEventListener(env->GetIsolate(), DebugEventDebugBreak);
5180 5 : v8::debug::DebugBreak(env->GetIsolate());
5181 15 : result = f->Call(context, env->Global(), argc, argv).ToLocalChecked();
5182 :
5183 : // Check that there was only one break event. Matching RegExp should not
5184 : // cause Break events.
5185 5 : CHECK_EQ(1, break_point_hit_count);
5186 5 : CHECK_EQ(0, strcmp("f", last_function_hit));
5187 5 : }
5188 : #endif // V8_INTERPRETED_REGEXP
5189 :
5190 : // Test which creates a context and sets embedder data on it. Checks that this
5191 : // data is set correctly and that when the debug event listener is called for
5192 : // break event in an eval statement the expected context is the one returned by
5193 : // Message.GetEventContext.
5194 23723 : TEST(EvalContextData) {
5195 5 : v8::HandleScope scope(CcTest::isolate());
5196 :
5197 : v8::Local<v8::Context> context_1;
5198 : v8::Local<v8::ObjectTemplate> global_template =
5199 : v8::Local<v8::ObjectTemplate>();
5200 5 : context_1 = v8::Context::New(CcTest::isolate(), nullptr, global_template);
5201 :
5202 5 : SetDebugEventListener(CcTest::isolate(), ContextCheckEventListener);
5203 :
5204 : // Default data value is undefined.
5205 5 : CHECK(context_1->GetEmbedderData(0)->IsUndefined());
5206 :
5207 : // Set and check a data value.
5208 5 : v8::Local<v8::String> data_1 = v8_str(CcTest::isolate(), "1");
5209 5 : context_1->SetEmbedderData(0, data_1);
5210 5 : CHECK(context_1->GetEmbedderData(0)->StrictEquals(data_1));
5211 :
5212 : // Simple test function with eval that causes a break.
5213 : const char* source = "function f() { eval('debugger;'); }";
5214 :
5215 : // Enter and run function in the context.
5216 : {
5217 : v8::Context::Scope context_scope(context_1);
5218 5 : expected_context = context_1;
5219 5 : expected_context_data = data_1;
5220 5 : v8::Local<v8::Function> f = CompileFunction(CcTest::isolate(), source, "f");
5221 15 : f->Call(context_1, context_1->Global(), 0, nullptr).ToLocalChecked();
5222 : }
5223 :
5224 5 : SetDebugEventListener(CcTest::isolate(), nullptr);
5225 :
5226 : // One time compile event and one time break event.
5227 5 : CHECK_GT(event_listener_hit_count, 2);
5228 5 : CheckDebuggerUnloaded();
5229 5 : }
5230 :
5231 :
5232 : // Debug event listener which counts the after compile events.
5233 : int after_compile_event_count = 0;
5234 55 : static void AfterCompileEventListener(const v8::Debug::EventDetails& details) {
5235 : // Count the number of scripts collected.
5236 55 : if (details.GetEvent() == v8::AfterCompile) {
5237 45 : after_compile_event_count++;
5238 : }
5239 55 : }
5240 :
5241 :
5242 : // Tests that after compile event is sent as many times as there are scripts
5243 : // compiled.
5244 23723 : TEST(AfterCompileEventWhenEventListenerIsReset) {
5245 5 : DebugLocalContext env;
5246 10 : v8::HandleScope scope(env->GetIsolate());
5247 5 : v8::Local<v8::Context> context = env.context();
5248 : const char* script = "var a=1";
5249 :
5250 5 : SetDebugEventListener(env->GetIsolate(), AfterCompileEventListener);
5251 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
5252 5 : .ToLocalChecked()
5253 : ->Run(context)
5254 5 : .ToLocalChecked();
5255 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
5256 :
5257 5 : SetDebugEventListener(env->GetIsolate(), AfterCompileEventListener);
5258 5 : v8::debug::DebugBreak(env->GetIsolate());
5259 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
5260 5 : .ToLocalChecked()
5261 : ->Run(context)
5262 5 : .ToLocalChecked();
5263 :
5264 : // Setting listener to nullptr should cause debugger unload.
5265 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
5266 : CheckDebuggerUnloaded();
5267 :
5268 : // Compilation cache should be disabled when debugger is active.
5269 5 : CHECK_EQ(2, after_compile_event_count);
5270 5 : }
5271 :
5272 :
5273 : // Syntax error event handler which counts a number of events.
5274 : int compile_error_event_count = 0;
5275 :
5276 : static void CompileErrorEventCounterClear() {
5277 5 : compile_error_event_count = 0;
5278 : }
5279 :
5280 35 : static void CompileErrorEventCounter(
5281 : const v8::Debug::EventDetails& event_details) {
5282 35 : v8::DebugEvent event = event_details.GetEvent();
5283 :
5284 35 : if (event == v8::CompileError) {
5285 15 : compile_error_event_count++;
5286 : }
5287 35 : }
5288 :
5289 :
5290 : // Tests that syntax error event is sent as many times as there are scripts
5291 : // with syntax error compiled.
5292 23723 : TEST(SyntaxErrorEventOnSyntaxException) {
5293 5 : DebugLocalContext env;
5294 10 : v8::HandleScope scope(env->GetIsolate());
5295 :
5296 : // For this test, we want to break on uncaught exceptions:
5297 5 : ChangeBreakOnException(false, true);
5298 :
5299 5 : SetDebugEventListener(env->GetIsolate(), CompileErrorEventCounter);
5300 5 : v8::Local<v8::Context> context = env.context();
5301 :
5302 : CompileErrorEventCounterClear();
5303 :
5304 : // Check initial state.
5305 5 : CHECK_EQ(0, compile_error_event_count);
5306 :
5307 : // Throws SyntaxError: Unexpected end of input
5308 10 : CHECK(
5309 : v8::Script::Compile(context, v8_str(env->GetIsolate(), "+++")).IsEmpty());
5310 5 : CHECK_EQ(1, compile_error_event_count);
5311 :
5312 10 : CHECK(v8::Script::Compile(context, v8_str(env->GetIsolate(), "/sel\\/: \\"))
5313 : .IsEmpty());
5314 5 : CHECK_EQ(2, compile_error_event_count);
5315 :
5316 : v8::Local<v8::Script> script =
5317 : v8::Script::Compile(context,
5318 5 : v8_str(env->GetIsolate(), "JSON.parse('1234:')"))
5319 5 : .ToLocalChecked();
5320 5 : CHECK_EQ(2, compile_error_event_count);
5321 10 : CHECK(script->Run(context).IsEmpty());
5322 5 : CHECK_EQ(3, compile_error_event_count);
5323 :
5324 : v8::Script::Compile(context,
5325 5 : v8_str(env->GetIsolate(), "new RegExp('/\\/\\\\');"))
5326 5 : .ToLocalChecked();
5327 5 : CHECK_EQ(3, compile_error_event_count);
5328 :
5329 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), "throw 1;"))
5330 5 : .ToLocalChecked();
5331 5 : CHECK_EQ(3, compile_error_event_count);
5332 5 : }
5333 :
5334 : // Tests that break event is sent when event listener is reset.
5335 23723 : TEST(BreakEventWhenEventListenerIsReset) {
5336 5 : DebugLocalContext env;
5337 10 : v8::HandleScope scope(env->GetIsolate());
5338 5 : v8::Local<v8::Context> context = env.context();
5339 : const char* script = "function f() {};";
5340 :
5341 5 : SetDebugEventListener(env->GetIsolate(), AfterCompileEventListener);
5342 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
5343 5 : .ToLocalChecked()
5344 : ->Run(context)
5345 5 : .ToLocalChecked();
5346 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
5347 :
5348 5 : SetDebugEventListener(env->GetIsolate(), AfterCompileEventListener);
5349 5 : v8::debug::DebugBreak(env->GetIsolate());
5350 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
5351 : env->Global()
5352 15 : ->Get(context, v8_str(env->GetIsolate(), "f"))
5353 5 : .ToLocalChecked());
5354 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
5355 :
5356 : // Setting event listener to nullptr should cause debugger unload.
5357 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
5358 : CheckDebuggerUnloaded();
5359 :
5360 : // Compilation cache should be disabled when debugger is active.
5361 5 : CHECK_EQ(1, after_compile_event_count);
5362 5 : }
5363 :
5364 :
5365 : static int exception_event_count = 0;
5366 5 : static void ExceptionEventListener(const v8::Debug::EventDetails& details) {
5367 5 : if (details.GetEvent() == v8::Exception) exception_event_count++;
5368 5 : }
5369 :
5370 : // Tests that exception event is sent when event listener is reset.
5371 23723 : TEST(ExceptionEventWhenEventListenerIsReset) {
5372 5 : DebugLocalContext env;
5373 10 : v8::HandleScope scope(env->GetIsolate());
5374 :
5375 5 : v8::Local<v8::Context> context = env.context();
5376 : // For this test, we want to break on uncaught exceptions:
5377 5 : ChangeBreakOnException(false, true);
5378 :
5379 5 : exception_event_count = 0;
5380 : const char* script = "function f() {throw new Error()};";
5381 :
5382 5 : SetDebugEventListener(env->GetIsolate(), AfterCompileEventListener);
5383 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
5384 5 : .ToLocalChecked()
5385 : ->Run(context)
5386 5 : .ToLocalChecked();
5387 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
5388 :
5389 5 : SetDebugEventListener(env->GetIsolate(), ExceptionEventListener);
5390 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
5391 : env->Global()
5392 15 : ->Get(context, v8_str(env->GetIsolate(), "f"))
5393 5 : .ToLocalChecked());
5394 15 : CHECK(f->Call(context, env->Global(), 0, nullptr).IsEmpty());
5395 :
5396 : // Setting event listener to nullptr should cause debugger unload.
5397 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
5398 : CheckDebuggerUnloaded();
5399 :
5400 5 : CHECK_EQ(1, exception_event_count);
5401 5 : }
5402 :
5403 :
5404 : // Tests after compile event is sent when there are some provisional
5405 : // breakpoints out of the scripts lines range.
5406 23723 : TEST(ProvisionalBreakpointOnLineOutOfRange) {
5407 5 : DebugLocalContext env;
5408 10 : v8::HandleScope scope(env->GetIsolate());
5409 5 : env.ExposeDebug();
5410 : const char* script = "function f() {};";
5411 : const char* resource_name = "test_resource";
5412 :
5413 5 : SetDebugEventListener(env->GetIsolate(), AfterCompileEventListener);
5414 5 : v8::Local<v8::Context> context = env.context();
5415 :
5416 : // Set a couple of provisional breakpoint on lines out of the script lines
5417 : // range.
5418 : int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name,
5419 5 : 3, -1 /* no column */);
5420 : int sbp2 =
5421 5 : SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name, 5, 5);
5422 :
5423 5 : after_compile_event_count = 0;
5424 :
5425 : v8::ScriptOrigin origin(v8_str(env->GetIsolate(), resource_name),
5426 : v8::Integer::New(env->GetIsolate(), 10),
5427 15 : v8::Integer::New(env->GetIsolate(), 1));
5428 : // Compile a script whose first line number is greater than the breakpoints'
5429 : // lines.
5430 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), script), &origin)
5431 5 : .ToLocalChecked()
5432 : ->Run(context)
5433 5 : .ToLocalChecked();
5434 :
5435 : // If the script is compiled successfully there is exactly one after compile
5436 : // event. In case of an exception in debugger code after compile event is not
5437 : // sent.
5438 5 : CHECK_EQ(1, after_compile_event_count);
5439 :
5440 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp1);
5441 5 : ClearBreakPointFromJS(env->GetIsolate(), sbp2);
5442 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
5443 : CheckDebuggerUnloaded();
5444 5 : }
5445 :
5446 20 : static void BreakEventListener(const v8::Debug::EventDetails& details) {
5447 20 : if (details.GetEvent() == v8::Break) break_point_hit_count++;
5448 20 : }
5449 :
5450 :
5451 : // Test that if DebugBreak is forced it is ignored when code from
5452 : // debug-delay.js is executed.
5453 23723 : TEST(NoDebugBreakInAfterCompileEventListener) {
5454 5 : DebugLocalContext env;
5455 10 : v8::HandleScope scope(env->GetIsolate());
5456 5 : v8::Local<v8::Context> context = env.context();
5457 :
5458 : // Register a debug event listener which sets the break flag and counts.
5459 5 : SetDebugEventListener(env->GetIsolate(), BreakEventListener);
5460 :
5461 : // Set the debug break flag.
5462 5 : v8::debug::DebugBreak(env->GetIsolate());
5463 :
5464 : // Create a function for testing stepping.
5465 : const char* src = "function f() { eval('var x = 10;'); } ";
5466 5 : v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
5467 :
5468 : // There should be only one break event.
5469 5 : CHECK_EQ(1, break_point_hit_count);
5470 :
5471 : // Set the debug break flag again.
5472 5 : v8::debug::DebugBreak(env->GetIsolate());
5473 15 : f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
5474 : // There should be one more break event when the script is evaluated in 'f'.
5475 5 : CHECK_EQ(2, break_point_hit_count);
5476 :
5477 : // Get rid of the debug event listener.
5478 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
5479 : CheckDebuggerUnloaded();
5480 5 : }
5481 :
5482 :
5483 : // Test that the debug break flag works with function.apply.
5484 23723 : TEST(DebugBreakFunctionApply) {
5485 5 : DebugLocalContext env;
5486 10 : v8::HandleScope scope(env->GetIsolate());
5487 5 : v8::Local<v8::Context> context = env.context();
5488 :
5489 : // Create a function for testing breaking in apply.
5490 : v8::Local<v8::Function> foo = CompileFunction(
5491 : &env,
5492 : "function baz(x) { }"
5493 : "function bar(x) { baz(); }"
5494 : "function foo(){ bar.apply(this, [1]); }",
5495 5 : "foo");
5496 :
5497 : // Register a debug event listener which steps and counts.
5498 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakMax);
5499 :
5500 : // Set the debug break flag before calling the code using function.apply.
5501 5 : v8::debug::DebugBreak(env->GetIsolate());
5502 :
5503 : // Limit the number of debug breaks. This is a regression test for issue 493
5504 : // where this test would enter an infinite loop.
5505 5 : break_point_hit_count = 0;
5506 5 : max_break_point_hit_count = 10000; // 10000 => infinite loop.
5507 15 : foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
5508 :
5509 : // When keeping the debug break several break will happen.
5510 5 : CHECK_GT(break_point_hit_count, 1);
5511 :
5512 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
5513 : CheckDebuggerUnloaded();
5514 5 : }
5515 :
5516 :
5517 : v8::Local<v8::Context> debugee_context;
5518 : v8::Local<v8::Context> debugger_context;
5519 :
5520 :
5521 : // Property getter that checks that current and calling contexts
5522 : // are both the debugee contexts.
5523 5 : static void NamedGetterWithCallingContextCheck(
5524 : v8::Local<v8::String> name,
5525 : const v8::PropertyCallbackInfo<v8::Value>& info) {
5526 5 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(info.GetIsolate(), name), "a"));
5527 5 : v8::Local<v8::Context> current = info.GetIsolate()->GetCurrentContext();
5528 5 : CHECK(current == debugee_context);
5529 5 : CHECK(current != debugger_context);
5530 : info.GetReturnValue().Set(1);
5531 5 : }
5532 :
5533 :
5534 : // Debug event listener that checks if the first argument of a function is
5535 : // an object with property 'a' == 1. If the property has custom accessor
5536 : // this handler will eventually invoke it.
5537 15 : static void DebugEventGetAtgumentPropertyValue(
5538 : const v8::Debug::EventDetails& event_details) {
5539 15 : v8::DebugEvent event = event_details.GetEvent();
5540 15 : v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
5541 15 : if (event == v8::Break) {
5542 5 : break_point_hit_count++;
5543 10 : CHECK(debugger_context == CcTest::isolate()->GetCurrentContext());
5544 : v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(CompileRun(
5545 : "(function(exec_state) {\n"
5546 : " return (exec_state.frame(0).argumentValue(0).property('a').\n"
5547 : " value().value() == 1);\n"
5548 : "})"));
5549 : const int argc = 1;
5550 : v8::Local<v8::Value> argv[argc] = {exec_state};
5551 : v8::Local<v8::Value> result =
5552 10 : func->Call(debugger_context, exec_state, argc, argv).ToLocalChecked();
5553 5 : CHECK(result->IsTrue());
5554 : }
5555 15 : }
5556 :
5557 :
5558 23723 : TEST(CallingContextIsNotDebugContext) {
5559 5 : v8::internal::Debug* debug = CcTest::i_isolate()->debug();
5560 : // Create and enter a debugee context.
5561 5 : DebugLocalContext env;
5562 5 : v8::Isolate* isolate = env->GetIsolate();
5563 10 : v8::HandleScope scope(isolate);
5564 5 : env.ExposeDebug();
5565 :
5566 : // Save handles to the debugger and debugee contexts to be used in
5567 : // NamedGetterWithCallingContextCheck.
5568 5 : debugee_context = env.context();
5569 5 : debugger_context = v8::Utils::ToLocal(debug->debug_context());
5570 :
5571 : // Create object with 'a' property accessor.
5572 5 : v8::Local<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
5573 5 : named->SetAccessor(v8_str(isolate, "a"), NamedGetterWithCallingContextCheck);
5574 25 : CHECK(env->Global()
5575 : ->Set(debugee_context, v8_str(isolate, "obj"),
5576 : named->NewInstance(debugee_context).ToLocalChecked())
5577 : .FromJust());
5578 :
5579 : // Register the debug event listener
5580 5 : SetDebugEventListener(isolate, DebugEventGetAtgumentPropertyValue);
5581 :
5582 : // Create a function that invokes debugger.
5583 : v8::Local<v8::Function> foo = CompileFunction(
5584 : &env,
5585 : "function bar(x) { debugger; }"
5586 : "function foo(){ bar(obj); }",
5587 5 : "foo");
5588 :
5589 5 : break_point_hit_count = 0;
5590 15 : foo->Call(debugee_context, env->Global(), 0, nullptr).ToLocalChecked();
5591 5 : CHECK_EQ(1, break_point_hit_count);
5592 :
5593 5 : SetDebugEventListener(isolate, nullptr);
5594 5 : debugee_context = v8::Local<v8::Context>();
5595 5 : debugger_context = v8::Local<v8::Context>();
5596 : CheckDebuggerUnloaded();
5597 5 : }
5598 :
5599 :
5600 : static v8::Local<v8::Value> expected_callback_data;
5601 10 : static void DebugEventContextChecker(const v8::Debug::EventDetails& details) {
5602 20 : CHECK(details.GetEventContext() == expected_context);
5603 30 : CHECK(expected_callback_data->Equals(details.GetEventContext(),
5604 : details.GetCallbackData())
5605 : .FromJust());
5606 10 : }
5607 :
5608 :
5609 : // Check that event details contain context where debug event occurred.
5610 23723 : TEST(DebugEventContext) {
5611 5 : v8::Isolate* isolate = CcTest::isolate();
5612 5 : v8::HandleScope scope(isolate);
5613 5 : expected_context = v8::Context::New(isolate);
5614 5 : expected_callback_data = v8::Int32::New(isolate, 2010);
5615 : SetDebugEventListener(isolate, DebugEventContextChecker,
5616 5 : expected_callback_data);
5617 : v8::Context::Scope context_scope(expected_context);
5618 : v8::Script::Compile(expected_context,
5619 5 : v8_str(isolate, "(function(){debugger;})();"))
5620 5 : .ToLocalChecked()
5621 : ->Run(expected_context)
5622 5 : .ToLocalChecked();
5623 : expected_context.Clear();
5624 5 : SetDebugEventListener(isolate, nullptr);
5625 5 : expected_context_data = v8::Local<v8::Value>();
5626 5 : CheckDebuggerUnloaded();
5627 5 : }
5628 :
5629 :
5630 : static bool debug_event_break_deoptimize_done = false;
5631 :
5632 10 : static void DebugEventBreakDeoptimize(
5633 : const v8::Debug::EventDetails& event_details) {
5634 10 : v8::DebugEvent event = event_details.GetEvent();
5635 10 : v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
5636 10 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
5637 10 : if (event == v8::Break) {
5638 5 : if (!frame_function_name.IsEmpty()) {
5639 : // Get the name of the function.
5640 : const int argc = 2;
5641 : v8::Local<v8::Value> argv[argc] = {
5642 5 : exec_state, v8::Integer::New(CcTest::isolate(), 0)};
5643 : v8::Local<v8::Value> result =
5644 5 : frame_function_name->Call(context, exec_state, argc, argv)
5645 5 : .ToLocalChecked();
5646 5 : if (!result->IsUndefined()) {
5647 : char fn[80];
5648 5 : CHECK(result->IsString());
5649 : v8::Local<v8::String> function_name(
5650 5 : result->ToString(context).ToLocalChecked());
5651 5 : function_name->WriteUtf8(fn);
5652 5 : if (strcmp(fn, "bar") == 0) {
5653 5 : i::Deoptimizer::DeoptimizeAll(CcTest::i_isolate());
5654 5 : debug_event_break_deoptimize_done = true;
5655 : }
5656 : }
5657 : }
5658 :
5659 5 : v8::debug::DebugBreak(CcTest::isolate());
5660 : }
5661 10 : }
5662 :
5663 :
5664 : // Test deoptimization when execution is broken using the debug break stack
5665 : // check interrupt.
5666 23723 : TEST(DeoptimizeDuringDebugBreak) {
5667 5 : DebugLocalContext env;
5668 10 : v8::HandleScope scope(env->GetIsolate());
5669 5 : env.ExposeDebug();
5670 5 : v8::Local<v8::Context> context = env.context();
5671 :
5672 : // Create a function for checking the function when hitting a break point.
5673 : frame_function_name = CompileFunction(&env,
5674 : frame_function_name_source,
5675 5 : "frame_function_name");
5676 :
5677 : // Set a debug event listener which will keep interrupting execution until
5678 : // debug break. When inside function bar it will deoptimize all functions.
5679 : // This tests lazy deoptimization bailout for the stack check, as the first
5680 : // time in function bar when using debug break and no break points will be at
5681 : // the initial stack check.
5682 5 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakDeoptimize);
5683 :
5684 : // Compile and run function bar which will optimize it for some flag settings.
5685 5 : v8::Local<v8::Function> f = CompileFunction(&env, "function bar(){}", "bar");
5686 10 : f->Call(context, v8::Undefined(env->GetIsolate()), 0, nullptr)
5687 5 : .ToLocalChecked();
5688 :
5689 : // Set debug break and call bar again.
5690 5 : v8::debug::DebugBreak(env->GetIsolate());
5691 10 : f->Call(context, v8::Undefined(env->GetIsolate()), 0, nullptr)
5692 5 : .ToLocalChecked();
5693 :
5694 5 : CHECK(debug_event_break_deoptimize_done);
5695 :
5696 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
5697 5 : }
5698 :
5699 :
5700 5 : static void DebugEventBreakWithOptimizedStack(
5701 : const v8::Debug::EventDetails& event_details) {
5702 10 : v8::Isolate* isolate = event_details.GetEventContext()->GetIsolate();
5703 5 : v8::DebugEvent event = event_details.GetEvent();
5704 5 : v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
5705 5 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
5706 5 : if (event == v8::Break) {
5707 5 : if (!frame_function_name.IsEmpty()) {
5708 10 : for (int i = 0; i < 2; i++) {
5709 : const int argc = 2;
5710 : v8::Local<v8::Value> argv[argc] = {exec_state,
5711 10 : v8::Integer::New(isolate, i)};
5712 : // Get the name of the function in frame i.
5713 : v8::Local<v8::Value> result =
5714 10 : frame_function_name->Call(context, exec_state, argc, argv)
5715 10 : .ToLocalChecked();
5716 10 : CHECK(result->IsString());
5717 : v8::Local<v8::String> function_name(
5718 10 : result->ToString(context).ToLocalChecked());
5719 30 : CHECK(
5720 : function_name->Equals(context, v8_str(isolate, "loop")).FromJust());
5721 : // Get the name of the first argument in frame i.
5722 10 : result = frame_argument_name->Call(context, exec_state, argc, argv)
5723 10 : .ToLocalChecked();
5724 10 : CHECK(result->IsString());
5725 : v8::Local<v8::String> argument_name(
5726 10 : result->ToString(context).ToLocalChecked());
5727 30 : CHECK(argument_name->Equals(context, v8_str(isolate, "count"))
5728 : .FromJust());
5729 : // Get the value of the first argument in frame i. If the
5730 : // function is optimized the value will be undefined, otherwise
5731 : // the value will be '1 - i'.
5732 : //
5733 : // TODO(3141533): We should be able to get the real value for
5734 : // optimized frames.
5735 10 : result = frame_argument_value->Call(context, exec_state, argc, argv)
5736 10 : .ToLocalChecked();
5737 20 : CHECK(result->IsUndefined() ||
5738 : (result->Int32Value(context).FromJust() == 1 - i));
5739 : // Get the name of the first local variable.
5740 10 : result = frame_local_name->Call(context, exec_state, argc, argv)
5741 10 : .ToLocalChecked();
5742 10 : CHECK(result->IsString());
5743 : v8::Local<v8::String> local_name(
5744 10 : result->ToString(context).ToLocalChecked());
5745 30 : CHECK(local_name->Equals(context, v8_str(isolate, "local")).FromJust());
5746 : // Get the value of the first local variable. If the function
5747 : // is optimized the value will be undefined, otherwise it will
5748 : // be 42.
5749 : //
5750 : // TODO(3141533): We should be able to get the real value for
5751 : // optimized frames.
5752 10 : result = frame_local_value->Call(context, exec_state, argc, argv)
5753 10 : .ToLocalChecked();
5754 14 : CHECK(result->IsUndefined() ||
5755 : (result->Int32Value(context).FromJust() == 42));
5756 : }
5757 : }
5758 : }
5759 5 : }
5760 :
5761 :
5762 15 : static void ScheduleBreak(const v8::FunctionCallbackInfo<v8::Value>& args) {
5763 5 : SetDebugEventListener(args.GetIsolate(), DebugEventBreakWithOptimizedStack);
5764 5 : v8::debug::DebugBreak(args.GetIsolate());
5765 5 : }
5766 :
5767 :
5768 23723 : TEST(DebugBreakStackInspection) {
5769 5 : DebugLocalContext env;
5770 10 : v8::HandleScope scope(env->GetIsolate());
5771 5 : v8::Local<v8::Context> context = env.context();
5772 :
5773 : frame_function_name =
5774 5 : CompileFunction(&env, frame_function_name_source, "frame_function_name");
5775 : frame_argument_name =
5776 5 : CompileFunction(&env, frame_argument_name_source, "frame_argument_name");
5777 : frame_argument_value = CompileFunction(&env,
5778 : frame_argument_value_source,
5779 5 : "frame_argument_value");
5780 : frame_local_name =
5781 5 : CompileFunction(&env, frame_local_name_source, "frame_local_name");
5782 : frame_local_value =
5783 5 : CompileFunction(&env, frame_local_value_source, "frame_local_value");
5784 :
5785 : v8::Local<v8::FunctionTemplate> schedule_break_template =
5786 5 : v8::FunctionTemplate::New(env->GetIsolate(), ScheduleBreak);
5787 : v8::Local<v8::Function> schedule_break =
5788 5 : schedule_break_template->GetFunction(context).ToLocalChecked();
5789 20 : CHECK(env->Global()
5790 : ->Set(context, v8_str("scheduleBreak"), schedule_break)
5791 : .FromJust());
5792 :
5793 : const char* src =
5794 : "function loop(count) {"
5795 : " var local = 42;"
5796 : " if (count < 1) { scheduleBreak(); loop(count + 1); }"
5797 : "}"
5798 : "loop(0);";
5799 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), src))
5800 5 : .ToLocalChecked()
5801 : ->Run(context)
5802 5 : .ToLocalChecked();
5803 5 : }
5804 :
5805 :
5806 : // Test that setting the terminate execution flag during debug break processing.
5807 60 : static void TestDebugBreakInLoop(const char* loop_head,
5808 : const char** loop_bodies,
5809 : const char* loop_tail) {
5810 : // Receive 10 breaks for each test and then terminate JavaScript execution.
5811 : static const int kBreaksPerTest = 10;
5812 :
5813 390 : for (int i = 0; loop_bodies[i] != nullptr; i++) {
5814 : // Perform a lazy deoptimization after various numbers of breaks
5815 : // have been hit.
5816 :
5817 : EmbeddedVector<char, 1024> buffer;
5818 : SNPrintF(buffer, "function f() {%s%s%s}", loop_head, loop_bodies[i],
5819 330 : loop_tail);
5820 :
5821 330 : i::PrintF("%s\n", buffer.start());
5822 :
5823 1320 : for (int j = 0; j < 3; j++) {
5824 990 : break_point_hit_count_deoptimize = j;
5825 990 : if (j == 2) {
5826 330 : break_point_hit_count_deoptimize = kBreaksPerTest;
5827 : }
5828 :
5829 990 : break_point_hit_count = 0;
5830 990 : max_break_point_hit_count = kBreaksPerTest;
5831 990 : terminate_after_max_break_point_hit = true;
5832 :
5833 : // Function with infinite loop.
5834 990 : CompileRun(buffer.start());
5835 :
5836 : // Set the debug break to enter the debugger as soon as possible.
5837 990 : v8::debug::DebugBreak(CcTest::isolate());
5838 :
5839 : // Call function with infinite loop.
5840 : CompileRun("f();");
5841 990 : CHECK_EQ(kBreaksPerTest, break_point_hit_count);
5842 :
5843 990 : CHECK(!CcTest::isolate()->IsExecutionTerminating());
5844 : }
5845 : }
5846 60 : }
5847 :
5848 : static const char* loop_bodies_1[] = {"",
5849 : "g()",
5850 : "if (a == 0) { g() }",
5851 : "if (a == 1) { g() }",
5852 : "if (a == 0) { g() } else { h() }",
5853 : "if (a == 0) { continue }",
5854 : nullptr};
5855 :
5856 : static const char* loop_bodies_2[] = {
5857 : "if (a == 1) { continue }",
5858 : "switch (a) { case 1: g(); }",
5859 : "switch (a) { case 1: continue; }",
5860 : "switch (a) { case 1: g(); break; default: h() }",
5861 : "switch (a) { case 1: continue; break; default: h() }",
5862 : nullptr};
5863 :
5864 60 : void DebugBreakLoop(const char* loop_header, const char** loop_bodies,
5865 : const char* loop_footer) {
5866 60 : DebugLocalContext env;
5867 120 : v8::HandleScope scope(env->GetIsolate());
5868 :
5869 : // Register a debug event listener which sets the break flag and counts.
5870 60 : SetDebugEventListener(env->GetIsolate(), DebugEventBreakMax);
5871 :
5872 : CompileRun(
5873 : "var a = 1;\n"
5874 : "function g() { }\n"
5875 : "function h() { }");
5876 :
5877 60 : TestDebugBreakInLoop(loop_header, loop_bodies, loop_footer);
5878 :
5879 : // Get rid of the debug event listener.
5880 60 : SetDebugEventListener(env->GetIsolate(), nullptr);
5881 : CheckDebuggerUnloaded();
5882 60 : }
5883 :
5884 :
5885 23723 : TEST(DebugBreakInWhileTrue1) {
5886 5 : DebugBreakLoop("while (true) {", loop_bodies_1, "}");
5887 5 : }
5888 :
5889 :
5890 23723 : TEST(DebugBreakInWhileTrue2) {
5891 5 : DebugBreakLoop("while (true) {", loop_bodies_2, "}");
5892 5 : }
5893 :
5894 :
5895 23723 : TEST(DebugBreakInWhileCondition1) {
5896 5 : DebugBreakLoop("while (a == 1) {", loop_bodies_1, "}");
5897 5 : }
5898 :
5899 :
5900 23723 : TEST(DebugBreakInWhileCondition2) {
5901 5 : DebugBreakLoop("while (a == 1) {", loop_bodies_2, "}");
5902 5 : }
5903 :
5904 :
5905 23723 : TEST(DebugBreakInDoWhileTrue1) {
5906 5 : DebugBreakLoop("do {", loop_bodies_1, "} while (true)");
5907 5 : }
5908 :
5909 :
5910 23723 : TEST(DebugBreakInDoWhileTrue2) {
5911 5 : DebugBreakLoop("do {", loop_bodies_2, "} while (true)");
5912 5 : }
5913 :
5914 :
5915 23723 : TEST(DebugBreakInDoWhileCondition1) {
5916 5 : DebugBreakLoop("do {", loop_bodies_1, "} while (a == 1)");
5917 5 : }
5918 :
5919 :
5920 23723 : TEST(DebugBreakInDoWhileCondition2) {
5921 5 : DebugBreakLoop("do {", loop_bodies_2, "} while (a == 1)");
5922 5 : }
5923 :
5924 :
5925 23723 : TEST(DebugBreakInFor1) { DebugBreakLoop("for (;;) {", loop_bodies_1, "}"); }
5926 :
5927 :
5928 23723 : TEST(DebugBreakInFor2) { DebugBreakLoop("for (;;) {", loop_bodies_2, "}"); }
5929 :
5930 :
5931 23723 : TEST(DebugBreakInForCondition1) {
5932 5 : DebugBreakLoop("for (;a == 1;) {", loop_bodies_1, "}");
5933 5 : }
5934 :
5935 :
5936 23723 : TEST(DebugBreakInForCondition2) {
5937 5 : DebugBreakLoop("for (;a == 1;) {", loop_bodies_2, "}");
5938 5 : }
5939 :
5940 :
5941 : v8::Local<v8::Script> inline_script;
5942 :
5943 50 : static void DebugBreakInlineListener(
5944 : const v8::Debug::EventDetails& event_details) {
5945 50 : v8::DebugEvent event = event_details.GetEvent();
5946 50 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
5947 95 : if (event != v8::Break) return;
5948 :
5949 : int expected_frame_count = 4;
5950 5 : int expected_line_number[] = {1, 4, 7, 12};
5951 :
5952 : i::Handle<i::Object> compiled_script = v8::Utils::OpenHandle(*inline_script);
5953 : i::Handle<i::Script> source_script = i::Handle<i::Script>(i::Script::cast(
5954 : i::JSFunction::cast(*compiled_script)->shared()->script()));
5955 :
5956 5 : int break_id = CcTest::i_isolate()->debug()->break_id();
5957 : char script[128];
5958 : i::Vector<char> script_vector(script, sizeof(script));
5959 5 : SNPrintF(script_vector, "%%GetFrameCount(%d)", break_id);
5960 : v8::Local<v8::Value> result = CompileRun(script);
5961 :
5962 10 : int frame_count = result->Int32Value(context).FromJust();
5963 5 : CHECK_EQ(expected_frame_count, frame_count);
5964 :
5965 20 : for (int i = 0; i < frame_count; i++) {
5966 : // The 6. element in the returned array of GetFrameDetails contains the
5967 : // source position of that frame.
5968 20 : SNPrintF(script_vector, "%%GetFrameDetails(%d, %d)[6]", break_id, i);
5969 : v8::Local<v8::Value> result = CompileRun(script);
5970 40 : CHECK_EQ(expected_line_number[i],
5971 : i::Script::GetLineNumber(source_script,
5972 : result->Int32Value(context).FromJust()));
5973 : }
5974 5 : SetDebugEventListener(CcTest::isolate(), nullptr);
5975 5 : CcTest::isolate()->TerminateExecution();
5976 : }
5977 :
5978 :
5979 23723 : TEST(DebugBreakInline) {
5980 5 : i::FLAG_allow_natives_syntax = true;
5981 5 : DebugLocalContext env;
5982 10 : v8::HandleScope scope(env->GetIsolate());
5983 5 : v8::Local<v8::Context> context = env.context();
5984 : const char* source =
5985 : "function debug(b) { \n"
5986 : " if (b) debugger; \n"
5987 : "} \n"
5988 : "function f(b) { \n"
5989 : " debug(b) \n"
5990 : "}; \n"
5991 : "function g(b) { \n"
5992 : " f(b); \n"
5993 : "}; \n"
5994 : "g(false); \n"
5995 : "g(false); \n"
5996 : "%OptimizeFunctionOnNextCall(g); \n"
5997 : "g(true);";
5998 5 : SetDebugEventListener(env->GetIsolate(), DebugBreakInlineListener);
5999 : inline_script =
6000 5 : v8::Script::Compile(context, v8_str(env->GetIsolate(), source))
6001 10 : .ToLocalChecked();
6002 5 : inline_script->Run(context).ToLocalChecked();
6003 5 : }
6004 :
6005 :
6006 20 : static void DebugEventStepNext(
6007 : const v8::Debug::EventDetails& event_details) {
6008 20 : v8::DebugEvent event = event_details.GetEvent();
6009 20 : if (event == v8::Break) {
6010 10 : PrepareStep(StepNext);
6011 : }
6012 20 : }
6013 :
6014 :
6015 5 : static void RunScriptInANewCFrame(const char* source) {
6016 5 : v8::TryCatch try_catch(CcTest::isolate());
6017 : CompileRun(source);
6018 5 : CHECK(try_catch.HasCaught());
6019 5 : }
6020 :
6021 :
6022 23723 : TEST(Regress131642) {
6023 : // Bug description:
6024 : // When doing StepNext through the first script, the debugger is not reset
6025 : // after exiting through exception. A flawed implementation enabling the
6026 : // debugger to step into Array.prototype.forEach breaks inside the callback
6027 : // for forEach in the second script under the assumption that we are in a
6028 : // recursive call. In an attempt to step out, we crawl the stack using the
6029 : // recorded frame pointer from the first script and fail when not finding it
6030 : // on the stack.
6031 5 : DebugLocalContext env;
6032 10 : v8::HandleScope scope(env->GetIsolate());
6033 5 : SetDebugEventListener(env->GetIsolate(), DebugEventStepNext);
6034 :
6035 : // We step through the first script. It exits through an exception. We run
6036 : // this inside a new frame to record a different FP than the second script
6037 : // would expect.
6038 : const char* script_1 = "debugger; throw new Error();";
6039 5 : RunScriptInANewCFrame(script_1);
6040 :
6041 : // The second script uses forEach.
6042 : const char* script_2 = "[0].forEach(function() { });";
6043 : CompileRun(script_2);
6044 :
6045 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
6046 5 : }
6047 :
6048 :
6049 : // Import from test-heap.cc
6050 : namespace v8 {
6051 : namespace internal {
6052 : namespace heap {
6053 : int CountNativeContexts();
6054 : } // namespace heap
6055 : } // namespace internal
6056 : } // namespace v8
6057 :
6058 10 : static void NopListener(const v8::Debug::EventDetails& event_details) {
6059 10 : }
6060 :
6061 :
6062 23723 : TEST(DebuggerCreatesContextIffActive) {
6063 5 : DebugLocalContext env;
6064 10 : v8::HandleScope scope(env->GetIsolate());
6065 5 : CHECK_EQ(1, v8::internal::heap::CountNativeContexts());
6066 :
6067 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
6068 : CompileRun("debugger;");
6069 5 : CHECK_EQ(1, v8::internal::heap::CountNativeContexts());
6070 :
6071 5 : SetDebugEventListener(env->GetIsolate(), NopListener);
6072 : CompileRun("debugger;");
6073 5 : CHECK_EQ(2, v8::internal::heap::CountNativeContexts());
6074 :
6075 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
6076 5 : }
6077 :
6078 :
6079 23723 : TEST(LiveEditEnabled) {
6080 5 : v8::internal::FLAG_allow_natives_syntax = true;
6081 5 : LocalContext env;
6082 10 : v8::HandleScope scope(env->GetIsolate());
6083 5 : v8::debug::SetLiveEditEnabled(env->GetIsolate(), true);
6084 5 : CompileRun("%LiveEditCompareStrings('', '')");
6085 5 : }
6086 :
6087 :
6088 23718 : TEST(LiveEditDisabled) {
6089 0 : v8::internal::FLAG_allow_natives_syntax = true;
6090 0 : LocalContext env;
6091 0 : v8::HandleScope scope(env->GetIsolate());
6092 0 : v8::debug::SetLiveEditEnabled(env->GetIsolate(), false);
6093 0 : CompileRun("%LiveEditCompareStrings('', '')");
6094 0 : }
6095 :
6096 :
6097 23723 : TEST(PrecompiledFunction) {
6098 : // Regression test for crbug.com/346207. If we have preparse data, parsing the
6099 : // function in the presence of the debugger (and breakpoints) should still
6100 : // succeed. The bug was that preparsing was done lazily and parsing was done
6101 : // eagerly, so, the symbol streams didn't match.
6102 5 : DebugLocalContext env;
6103 10 : v8::HandleScope scope(env->GetIsolate());
6104 5 : env.ExposeDebug();
6105 5 : SetDebugEventListener(env->GetIsolate(), DebugBreakInlineListener);
6106 :
6107 : v8::Local<v8::Function> break_here =
6108 5 : CompileFunction(&env, "function break_here(){}", "break_here");
6109 5 : SetBreakPoint(break_here, 0);
6110 :
6111 : const char* source =
6112 : "var a = b = c = 1; \n"
6113 : "function this_is_lazy() { \n"
6114 : // This symbol won't appear in the preparse data.
6115 : " var a; \n"
6116 : "} \n"
6117 : "function bar() { \n"
6118 : " return \"bar\"; \n"
6119 : "}; \n"
6120 : "a = b = c = 2; \n"
6121 : "bar(); \n";
6122 5 : v8::Local<v8::Value> result = ParserCacheCompileRun(source);
6123 5 : CHECK(result->IsString());
6124 10 : v8::String::Utf8Value utf8(env->GetIsolate(), result);
6125 5 : CHECK_EQ(0, strcmp("bar", *utf8));
6126 :
6127 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
6128 : CheckDebuggerUnloaded();
6129 5 : }
6130 :
6131 :
6132 5000 : static void DebugBreakStackTraceListener(
6133 : const v8::Debug::EventDetails& event_details) {
6134 5000 : v8::StackTrace::CurrentStackTrace(CcTest::isolate(), 10);
6135 5000 : }
6136 :
6137 :
6138 5000 : static void AddDebugBreak(const v8::FunctionCallbackInfo<v8::Value>& args) {
6139 5000 : v8::debug::DebugBreak(args.GetIsolate());
6140 5000 : }
6141 :
6142 :
6143 23723 : TEST(DebugBreakStackTrace) {
6144 5 : DebugLocalContext env;
6145 10 : v8::HandleScope scope(env->GetIsolate());
6146 5 : SetDebugEventListener(env->GetIsolate(), DebugBreakStackTraceListener);
6147 5 : v8::Local<v8::Context> context = env.context();
6148 : v8::Local<v8::FunctionTemplate> add_debug_break_template =
6149 5 : v8::FunctionTemplate::New(env->GetIsolate(), AddDebugBreak);
6150 : v8::Local<v8::Function> add_debug_break =
6151 5 : add_debug_break_template->GetFunction(context).ToLocalChecked();
6152 20 : CHECK(env->Global()
6153 : ->Set(context, v8_str("add_debug_break"), add_debug_break)
6154 : .FromJust());
6155 :
6156 : CompileRun("(function loop() {"
6157 : " for (var j = 0; j < 1000; j++) {"
6158 : " for (var i = 0; i < 1000; i++) {"
6159 : " if (i == 999) add_debug_break();"
6160 : " }"
6161 : " }"
6162 : "})()");
6163 5 : }
6164 :
6165 :
6166 23718 : v8::base::Semaphore terminate_requested_semaphore(0);
6167 23718 : v8::base::Semaphore terminate_fired_semaphore(0);
6168 : bool terminate_already_fired = false;
6169 :
6170 :
6171 10 : static void DebugBreakTriggerTerminate(
6172 : const v8::Debug::EventDetails& event_details) {
6173 20 : if (event_details.GetEvent() != v8::Break || terminate_already_fired) return;
6174 5 : terminate_requested_semaphore.Signal();
6175 : // Wait for at most 2 seconds for the terminate request.
6176 5 : CHECK(terminate_fired_semaphore.WaitFor(v8::base::TimeDelta::FromSeconds(2)));
6177 5 : terminate_already_fired = true;
6178 : }
6179 :
6180 :
6181 5 : class TerminationThread : public v8::base::Thread {
6182 : public:
6183 : explicit TerminationThread(v8::Isolate* isolate)
6184 5 : : Thread(Options("terminator")), isolate_(isolate) {}
6185 :
6186 5 : virtual void Run() {
6187 5 : terminate_requested_semaphore.Wait();
6188 5 : isolate_->TerminateExecution();
6189 5 : terminate_fired_semaphore.Signal();
6190 5 : }
6191 :
6192 : private:
6193 : v8::Isolate* isolate_;
6194 : };
6195 :
6196 :
6197 23723 : TEST(DebugBreakOffThreadTerminate) {
6198 5 : DebugLocalContext env;
6199 5 : v8::Isolate* isolate = env->GetIsolate();
6200 10 : v8::HandleScope scope(isolate);
6201 5 : SetDebugEventListener(isolate, DebugBreakTriggerTerminate);
6202 : TerminationThread terminator(isolate);
6203 5 : terminator.Start();
6204 10 : v8::TryCatch try_catch(env->GetIsolate());
6205 5 : v8::debug::DebugBreak(isolate);
6206 : CompileRun("while (true);");
6207 5 : CHECK(try_catch.HasTerminated());
6208 5 : }
6209 :
6210 :
6211 50 : static void DebugEventExpectNoException(
6212 : const v8::Debug::EventDetails& event_details) {
6213 50 : v8::DebugEvent event = event_details.GetEvent();
6214 50 : CHECK_NE(v8::Exception, event);
6215 50 : }
6216 :
6217 :
6218 5 : static void TryCatchWrappedThrowCallback(
6219 5 : const v8::FunctionCallbackInfo<v8::Value>& args) {
6220 5 : v8::TryCatch try_catch(args.GetIsolate());
6221 : CompileRun("throw 'rejection';");
6222 5 : CHECK(try_catch.HasCaught());
6223 5 : }
6224 :
6225 :
6226 23723 : TEST(DebugPromiseInterceptedByTryCatch) {
6227 5 : DebugLocalContext env;
6228 5 : v8::Isolate* isolate = env->GetIsolate();
6229 10 : v8::HandleScope scope(isolate);
6230 5 : SetDebugEventListener(isolate, &DebugEventExpectNoException);
6231 5 : v8::Local<v8::Context> context = env.context();
6232 5 : ChangeBreakOnException(false, true);
6233 :
6234 : v8::Local<v8::FunctionTemplate> fun =
6235 5 : v8::FunctionTemplate::New(isolate, TryCatchWrappedThrowCallback);
6236 25 : CHECK(env->Global()
6237 : ->Set(context, v8_str("fun"),
6238 : fun->GetFunction(context).ToLocalChecked())
6239 : .FromJust());
6240 :
6241 : CompileRun("var p = new Promise(function(res, rej) { fun(); res(); });");
6242 : CompileRun(
6243 : "var r;"
6244 : "p.then(function() { r = 'resolved'; },"
6245 : " function() { r = 'rejected'; });");
6246 15 : CHECK(CompileRun("r")->Equals(context, v8_str("resolved")).FromJust());
6247 5 : }
6248 :
6249 :
6250 : static int exception_event_counter = 0;
6251 :
6252 :
6253 55 : static void DebugEventCountException(
6254 : const v8::Debug::EventDetails& event_details) {
6255 55 : v8::DebugEvent event = event_details.GetEvent();
6256 55 : if (event == v8::Exception) exception_event_counter++;
6257 55 : }
6258 :
6259 :
6260 5 : static void ThrowCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
6261 : CompileRun("throw 'rejection';");
6262 5 : }
6263 :
6264 :
6265 23723 : TEST(DebugPromiseRejectedByCallback) {
6266 5 : DebugLocalContext env;
6267 5 : v8::Isolate* isolate = env->GetIsolate();
6268 10 : v8::HandleScope scope(isolate);
6269 5 : SetDebugEventListener(isolate, &DebugEventCountException);
6270 5 : v8::Local<v8::Context> context = env.context();
6271 5 : ChangeBreakOnException(false, true);
6272 5 : exception_event_counter = 0;
6273 :
6274 : v8::Local<v8::FunctionTemplate> fun =
6275 5 : v8::FunctionTemplate::New(isolate, ThrowCallback);
6276 25 : CHECK(env->Global()
6277 : ->Set(context, v8_str("fun"),
6278 : fun->GetFunction(context).ToLocalChecked())
6279 : .FromJust());
6280 :
6281 : CompileRun("var p = new Promise(function(res, rej) { fun(); res(); });");
6282 : CompileRun(
6283 : "var r;"
6284 : "p.then(function() { r = 'resolved'; },"
6285 : " function(e) { r = 'rejected' + e; });");
6286 15 : CHECK(
6287 : CompileRun("r")->Equals(context, v8_str("rejectedrejection")).FromJust());
6288 5 : CHECK_EQ(1, exception_event_counter);
6289 5 : }
6290 :
6291 :
6292 175 : static void DebugHarmonyScopingListener(
6293 : const v8::Debug::EventDetails& event_details) {
6294 175 : v8::DebugEvent event = event_details.GetEvent();
6295 340 : if (event != v8::Break) return;
6296 :
6297 10 : int break_id = CcTest::i_isolate()->debug()->break_id();
6298 :
6299 : char script[128];
6300 : i::Vector<char> script_vector(script, sizeof(script));
6301 10 : SNPrintF(script_vector, "%%GetFrameCount(%d)", break_id);
6302 10 : ExpectInt32(script, 1);
6303 :
6304 10 : SNPrintF(script_vector, "var frame = new FrameMirror(%d, 0);", break_id);
6305 : CompileRun(script);
6306 10 : ExpectInt32("frame.evaluate('x').value_", 1);
6307 10 : ExpectInt32("frame.evaluate('y').value_", 2);
6308 :
6309 : CompileRun("var allScopes = frame.allScopes()");
6310 10 : ExpectInt32("allScopes.length", 2);
6311 :
6312 10 : ExpectBoolean("allScopes[0].scopeType() === ScopeType.Script", true);
6313 :
6314 10 : ExpectInt32("allScopes[0].scopeObject().value_.x", 1);
6315 :
6316 10 : ExpectInt32("allScopes[0].scopeObject().value_.y", 2);
6317 :
6318 : CompileRun("allScopes[0].setVariableValue('x', 5);");
6319 : CompileRun("allScopes[0].setVariableValue('y', 6);");
6320 10 : ExpectInt32("frame.evaluate('x + y').value_", 11);
6321 : }
6322 :
6323 :
6324 23723 : TEST(DebugBreakInLexicalScopes) {
6325 5 : i::FLAG_allow_natives_syntax = true;
6326 :
6327 5 : DebugLocalContext env;
6328 5 : v8::Isolate* isolate = env->GetIsolate();
6329 10 : v8::HandleScope scope(isolate);
6330 5 : SetDebugEventListener(isolate, DebugHarmonyScopingListener);
6331 :
6332 : CompileRun(
6333 : "'use strict'; \n"
6334 : "let x = 1; \n");
6335 : ExpectInt32(
6336 : "'use strict'; \n"
6337 : "let y = 2; \n"
6338 : "debugger; \n"
6339 : "x * y",
6340 5 : 30);
6341 : ExpectInt32(
6342 : "x = 1; y = 2; \n"
6343 : "debugger;"
6344 : "x * y",
6345 5 : 30);
6346 5 : }
6347 :
6348 : static int after_compile_handler_depth = 0;
6349 5 : static void HandleInterrupt(v8::Isolate* isolate, void* data) {
6350 5 : CHECK_EQ(0, after_compile_handler_depth);
6351 5 : }
6352 :
6353 5 : static void NoInterruptsOnDebugEvent(
6354 : const v8::Debug::EventDetails& event_details) {
6355 5 : if (event_details.GetEvent() != v8::AfterCompile) return;
6356 5 : ++after_compile_handler_depth;
6357 : // Do not allow nested AfterCompile events.
6358 5 : CHECK_LE(after_compile_handler_depth, 1);
6359 10 : v8::Isolate* isolate = event_details.GetEventContext()->GetIsolate();
6360 5 : v8::Isolate::AllowJavascriptExecutionScope allow_script(isolate);
6361 5 : isolate->RequestInterrupt(&HandleInterrupt, nullptr);
6362 : CompileRun("function foo() {}; foo();");
6363 5 : --after_compile_handler_depth;
6364 : }
6365 :
6366 23723 : TEST(NoInterruptsInDebugListener) {
6367 5 : DebugLocalContext env;
6368 5 : SetDebugEventListener(env->GetIsolate(), NoInterruptsOnDebugEvent);
6369 : CompileRun("void(0);");
6370 5 : }
6371 :
6372 23723 : TEST(BreakLocationIterator) {
6373 5 : DebugLocalContext env;
6374 5 : v8::Isolate* isolate = env->GetIsolate();
6375 5 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
6376 10 : v8::HandleScope scope(isolate);
6377 :
6378 : v8::Local<v8::Value> result = CompileRun(
6379 : "function f() {\n"
6380 : " debugger; \n"
6381 : " f(); \n"
6382 : " debugger; \n"
6383 : "} \n"
6384 : "f");
6385 : Handle<i::Object> function_obj = v8::Utils::OpenHandle(*result);
6386 : Handle<i::JSFunction> function = Handle<i::JSFunction>::cast(function_obj);
6387 : Handle<i::SharedFunctionInfo> shared(function->shared());
6388 :
6389 : EnableDebugger(isolate);
6390 5 : CHECK(i_isolate->debug()->EnsureBreakInfo(shared));
6391 :
6392 5 : Handle<i::DebugInfo> debug_info(shared->GetDebugInfo());
6393 :
6394 : {
6395 5 : i::BreakIterator iterator(debug_info);
6396 5 : CHECK(iterator.GetBreakLocation().IsDebuggerStatement());
6397 5 : CHECK_EQ(17, iterator.GetBreakLocation().position());
6398 5 : iterator.Next();
6399 10 : CHECK(iterator.GetBreakLocation().IsDebugBreakSlot());
6400 5 : CHECK_EQ(32, iterator.GetBreakLocation().position());
6401 5 : iterator.Next();
6402 5 : CHECK(iterator.GetBreakLocation().IsCall());
6403 5 : CHECK_EQ(32, iterator.GetBreakLocation().position());
6404 5 : iterator.Next();
6405 5 : CHECK(iterator.GetBreakLocation().IsDebuggerStatement());
6406 5 : CHECK_EQ(47, iterator.GetBreakLocation().position());
6407 5 : iterator.Next();
6408 5 : CHECK(iterator.GetBreakLocation().IsReturn());
6409 5 : CHECK_EQ(60, iterator.GetBreakLocation().position());
6410 5 : iterator.Next();
6411 5 : CHECK(iterator.Done());
6412 : }
6413 :
6414 : DisableDebugger(isolate);
6415 5 : }
6416 :
6417 : size_t current_action = 0;
6418 : StepAction actions[] = {StepNext, StepNext};
6419 25 : static void DebugStepOverFunctionWithCaughtExceptionListener(
6420 : const v8::Debug::EventDetails& event_details) {
6421 25 : v8::DebugEvent event = event_details.GetEvent();
6422 25 : if (event != v8::Break) return;
6423 20 : ++break_point_hit_count;
6424 20 : if (current_action >= 2) return;
6425 20 : PrepareStep(actions[current_action]);
6426 : }
6427 :
6428 23723 : TEST(DebugStepOverFunctionWithCaughtException) {
6429 5 : i::FLAG_allow_natives_syntax = true;
6430 :
6431 5 : DebugLocalContext env;
6432 5 : v8::Isolate* isolate = env->GetIsolate();
6433 10 : v8::HandleScope scope(isolate);
6434 : SetDebugEventListener(isolate,
6435 5 : DebugStepOverFunctionWithCaughtExceptionListener);
6436 :
6437 5 : break_point_hit_count = 0;
6438 : CompileRun(
6439 : "function foo() {\n"
6440 : " try { throw new Error(); } catch (e) {}\n"
6441 : "}\n"
6442 : "debugger;\n"
6443 : "foo();\n"
6444 : "foo();\n");
6445 :
6446 5 : SetDebugEventListener(env->GetIsolate(), nullptr);
6447 5 : CHECK_EQ(4, break_point_hit_count);
6448 5 : }
6449 :
6450 : bool out_of_memory_callback_called = false;
6451 5 : void OutOfMemoryCallback(void* data) {
6452 5 : out_of_memory_callback_called = true;
6453 5 : reinterpret_cast<v8::Isolate*>(data)->IncreaseHeapLimitForDebugging();
6454 5 : }
6455 :
6456 23723 : UNINITIALIZED_TEST(DebugSetOutOfMemoryListener) {
6457 : v8::Isolate::CreateParams create_params;
6458 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
6459 : create_params.constraints.set_max_old_space_size(10);
6460 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
6461 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
6462 : {
6463 : v8::Isolate::Scope i_scope(isolate);
6464 10 : v8::HandleScope scope(isolate);
6465 5 : LocalContext context(isolate);
6466 : v8::debug::SetOutOfMemoryCallback(isolate, OutOfMemoryCallback,
6467 5 : reinterpret_cast<void*>(isolate));
6468 5 : CHECK(!out_of_memory_callback_called);
6469 : // The following allocation fails unless the out-of-memory callback
6470 : // increases the heap limit.
6471 : int length = 10 * i::MB / i::kPointerSize;
6472 5 : i_isolate->factory()->NewFixedArray(length, i::TENURED);
6473 5 : CHECK(out_of_memory_callback_called);
6474 : }
6475 5 : isolate->Dispose();
6476 5 : }
6477 :
6478 23723 : TEST(DebugCoverage) {
6479 5 : i::FLAG_always_opt = false;
6480 5 : LocalContext env;
6481 5 : v8::Isolate* isolate = env->GetIsolate();
6482 10 : v8::HandleScope scope(isolate);
6483 5 : v8::debug::Coverage::SelectMode(isolate, v8::debug::Coverage::kPreciseCount);
6484 : v8::Local<v8::String> source = v8_str(
6485 : "function f() {\n"
6486 : "}\n"
6487 : "f();\n"
6488 5 : "f();");
6489 5 : CompileRun(source);
6490 5 : v8::debug::Coverage coverage = v8::debug::Coverage::CollectPrecise(isolate);
6491 5 : CHECK_EQ(1u, coverage.ScriptCount());
6492 5 : v8::debug::Coverage::ScriptData script_data = coverage.GetScriptData(0);
6493 5 : v8::Local<v8::debug::Script> script = script_data.GetScript();
6494 15 : CHECK(script->Source()
6495 : .ToLocalChecked()
6496 : ->Equals(env.local(), source)
6497 : .FromMaybe(false));
6498 :
6499 5 : CHECK_EQ(2u, script_data.FunctionCount());
6500 : v8::debug::Coverage::FunctionData function_data =
6501 5 : script_data.GetFunctionData(0);
6502 : v8::debug::Location start =
6503 5 : script->GetSourceLocation(function_data.StartOffset());
6504 : v8::debug::Location end =
6505 5 : script->GetSourceLocation(function_data.EndOffset());
6506 5 : CHECK_EQ(0, start.GetLineNumber());
6507 5 : CHECK_EQ(0, start.GetColumnNumber());
6508 5 : CHECK_EQ(3, end.GetLineNumber());
6509 5 : CHECK_EQ(4, end.GetColumnNumber());
6510 5 : CHECK_EQ(1, function_data.Count());
6511 :
6512 10 : function_data = script_data.GetFunctionData(1);
6513 5 : start = script->GetSourceLocation(function_data.StartOffset());
6514 5 : end = script->GetSourceLocation(function_data.EndOffset());
6515 5 : CHECK_EQ(0, start.GetLineNumber());
6516 5 : CHECK_EQ(0, start.GetColumnNumber());
6517 5 : CHECK_EQ(1, end.GetLineNumber());
6518 5 : CHECK_EQ(1, end.GetColumnNumber());
6519 10 : CHECK_EQ(2, function_data.Count());
6520 5 : }
6521 :
6522 : namespace {
6523 5 : v8::debug::Coverage::ScriptData GetScriptDataAndDeleteCoverage(
6524 : v8::Isolate* isolate) {
6525 5 : v8::debug::Coverage coverage = v8::debug::Coverage::CollectPrecise(isolate);
6526 5 : CHECK_EQ(1u, coverage.ScriptCount());
6527 10 : return coverage.GetScriptData(0);
6528 : }
6529 : } // namespace
6530 :
6531 23723 : TEST(DebugCoverageWithCoverageOutOfScope) {
6532 5 : i::FLAG_always_opt = false;
6533 5 : LocalContext env;
6534 5 : v8::Isolate* isolate = env->GetIsolate();
6535 10 : v8::HandleScope scope(isolate);
6536 5 : v8::debug::Coverage::SelectMode(isolate, v8::debug::Coverage::kPreciseCount);
6537 : v8::Local<v8::String> source = v8_str(
6538 : "function f() {\n"
6539 : "}\n"
6540 : "f();\n"
6541 5 : "f();");
6542 5 : CompileRun(source);
6543 : v8::debug::Coverage::ScriptData script_data =
6544 5 : GetScriptDataAndDeleteCoverage(isolate);
6545 5 : v8::Local<v8::debug::Script> script = script_data.GetScript();
6546 15 : CHECK(script->Source()
6547 : .ToLocalChecked()
6548 : ->Equals(env.local(), source)
6549 : .FromMaybe(false));
6550 :
6551 5 : CHECK_EQ(2u, script_data.FunctionCount());
6552 : v8::debug::Coverage::FunctionData function_data =
6553 5 : script_data.GetFunctionData(0);
6554 :
6555 5 : CHECK_EQ(0, function_data.StartOffset());
6556 5 : CHECK_EQ(26, function_data.EndOffset());
6557 :
6558 : v8::debug::Location start =
6559 5 : script->GetSourceLocation(function_data.StartOffset());
6560 : v8::debug::Location end =
6561 5 : script->GetSourceLocation(function_data.EndOffset());
6562 5 : CHECK_EQ(0, start.GetLineNumber());
6563 5 : CHECK_EQ(0, start.GetColumnNumber());
6564 5 : CHECK_EQ(3, end.GetLineNumber());
6565 5 : CHECK_EQ(4, end.GetColumnNumber());
6566 5 : CHECK_EQ(1, function_data.Count());
6567 :
6568 10 : function_data = script_data.GetFunctionData(1);
6569 5 : start = script->GetSourceLocation(function_data.StartOffset());
6570 5 : end = script->GetSourceLocation(function_data.EndOffset());
6571 :
6572 5 : CHECK_EQ(0, function_data.StartOffset());
6573 5 : CHECK_EQ(16, function_data.EndOffset());
6574 :
6575 5 : CHECK_EQ(0, start.GetLineNumber());
6576 5 : CHECK_EQ(0, start.GetColumnNumber());
6577 5 : CHECK_EQ(1, end.GetLineNumber());
6578 5 : CHECK_EQ(1, end.GetColumnNumber());
6579 10 : CHECK_EQ(2, function_data.Count());
6580 5 : }
6581 :
6582 : namespace {
6583 5 : v8::debug::Coverage::FunctionData GetFunctionDataAndDeleteCoverage(
6584 : v8::Isolate* isolate) {
6585 5 : v8::debug::Coverage coverage = v8::debug::Coverage::CollectPrecise(isolate);
6586 5 : CHECK_EQ(1u, coverage.ScriptCount());
6587 :
6588 5 : v8::debug::Coverage::ScriptData script_data = coverage.GetScriptData(0);
6589 :
6590 5 : CHECK_EQ(2u, script_data.FunctionCount());
6591 : v8::debug::Coverage::FunctionData function_data =
6592 5 : script_data.GetFunctionData(0);
6593 5 : CHECK_EQ(1, function_data.Count());
6594 5 : CHECK_EQ(0, function_data.StartOffset());
6595 5 : CHECK_EQ(26, function_data.EndOffset());
6596 5 : return function_data;
6597 : }
6598 : } // namespace
6599 :
6600 23723 : TEST(DebugCoverageWithScriptDataOutOfScope) {
6601 5 : i::FLAG_always_opt = false;
6602 5 : LocalContext env;
6603 5 : v8::Isolate* isolate = env->GetIsolate();
6604 10 : v8::HandleScope scope(isolate);
6605 5 : v8::debug::Coverage::SelectMode(isolate, v8::debug::Coverage::kPreciseCount);
6606 : v8::Local<v8::String> source = v8_str(
6607 : "function f() {\n"
6608 : "}\n"
6609 : "f();\n"
6610 5 : "f();");
6611 5 : CompileRun(source);
6612 :
6613 : v8::debug::Coverage::FunctionData function_data =
6614 5 : GetFunctionDataAndDeleteCoverage(isolate);
6615 5 : CHECK_EQ(1, function_data.Count());
6616 5 : CHECK_EQ(0, function_data.StartOffset());
6617 10 : CHECK_EQ(26, function_data.EndOffset());
6618 5 : }
6619 :
6620 23723 : TEST(BuiltinsExceptionPrediction) {
6621 5 : v8::Isolate* isolate = CcTest::isolate();
6622 5 : v8::HandleScope handle_scope(isolate);
6623 5 : v8::Context::New(isolate);
6624 :
6625 : i::Builtins* builtins = CcTest::i_isolate()->builtins();
6626 : bool fail = false;
6627 3510 : for (int i = 0; i < i::Builtins::builtin_count; i++) {
6628 : Code* builtin = builtins->builtin(i);
6629 :
6630 3505 : if (builtin->kind() != Code::BUILTIN) continue;
6631 :
6632 : auto prediction = builtin->GetBuiltinCatchPrediction();
6633 : USE(prediction);
6634 : }
6635 5 : CHECK(!fail);
6636 5 : }
6637 :
6638 23723 : TEST(DebugGetPossibleBreakpointsReturnLocations) {
6639 5 : LocalContext env;
6640 5 : v8::Isolate* isolate = env->GetIsolate();
6641 10 : v8::HandleScope scope(isolate);
6642 : v8::Local<v8::String> source = v8_str(
6643 : "function fib(x) {\n"
6644 : " if (x < 0) return;\n"
6645 : " if (x === 0) return 1;\n"
6646 : " if (x === 1) return fib(0);\n"
6647 : " return x > 2 ? fib(x - 1) + fib(x - 2) : fib(1) + fib(0);\n"
6648 5 : "}");
6649 5 : CompileRun(source);
6650 5 : v8::PersistentValueVector<v8::debug::Script> scripts(isolate);
6651 5 : v8::debug::GetLoadedScripts(isolate, scripts);
6652 5 : CHECK_EQ(scripts.Size(), 1);
6653 : std::vector<v8::debug::BreakLocation> locations;
6654 10 : CHECK(scripts.Get(0)->GetPossibleBreakpoints(
6655 : v8::debug::Location(0, 17), v8::debug::Location(), true, &locations));
6656 : int returns_count = 0;
6657 165 : for (size_t i = 0; i < locations.size(); ++i) {
6658 80 : if (locations[i].type() == v8::debug::kReturnBreakLocation) {
6659 20 : ++returns_count;
6660 : }
6661 : }
6662 : // With Ignition we generate one return location per return statement,
6663 : // each has line = 5, column = 0 as statement position.
6664 10 : CHECK_EQ(returns_count, 4);
6665 5 : }
6666 :
6667 23723 : TEST(DebugEvaluateNoSideEffect) {
6668 5 : LocalContext env;
6669 3775 : i::Isolate* isolate = CcTest::i_isolate();
6670 : i::HandleScope scope(isolate);
6671 : std::vector<i::Handle<i::JSFunction>> all_functions;
6672 : {
6673 5 : i::HeapIterator iterator(isolate->heap());
6674 39975 : while (i::HeapObject* obj = iterator.next()) {
6675 76165 : if (!obj->IsJSFunction()) continue;
6676 3775 : i::JSFunction* fun = i::JSFunction::cast(obj);
6677 3775 : all_functions.emplace_back(fun);
6678 5 : }
6679 : }
6680 :
6681 : // Perform side effect check on all built-in functions. The side effect check
6682 : // itself contains additional sanity checks.
6683 7560 : for (i::Handle<i::JSFunction> fun : all_functions) {
6684 : bool failed = false;
6685 : {
6686 3775 : i::NoSideEffectScope scope(isolate, true);
6687 3775 : failed = !isolate->debug()->PerformSideEffectCheck(fun);
6688 : }
6689 3775 : if (failed) isolate->clear_pending_exception();
6690 5 : }
6691 71159 : }
|