blob: dd483c06d569bc7f87120a92405126022c5ab9e5 [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010028#include <stdlib.h>
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010029
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030#include "src/v8.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000031
Ben Murdochb8a8cc12014-11-26 15:28:44 +000032#include "src/api.h"
33#include "src/base/platform/condition-variable.h"
34#include "src/base/platform/platform.h"
35#include "src/compilation-cache.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000036#include "src/debug/debug.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000037#include "src/deoptimizer.h"
38#include "src/frames.h"
39#include "src/utils.h"
40#include "test/cctest/cctest.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000041
42
Ben Murdochb8a8cc12014-11-26 15:28:44 +000043using ::v8::base::Mutex;
44using ::v8::base::LockGuard;
45using ::v8::base::ConditionVariable;
46using ::v8::base::OS;
47using ::v8::base::Semaphore;
Steve Blocka7e24c12009-10-30 11:49:00 +000048using ::v8::internal::EmbeddedVector;
49using ::v8::internal::Object;
Steve Blocka7e24c12009-10-30 11:49:00 +000050using ::v8::internal::Handle;
51using ::v8::internal::Heap;
52using ::v8::internal::JSGlobalProxy;
53using ::v8::internal::Code;
54using ::v8::internal::Debug;
Steve Blocka7e24c12009-10-30 11:49:00 +000055using ::v8::internal::CommandMessage;
56using ::v8::internal::CommandMessageQueue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000057using ::v8::internal::StackFrame;
Steve Blocka7e24c12009-10-30 11:49:00 +000058using ::v8::internal::StepAction;
59using ::v8::internal::StepIn; // From StepAction enum
60using ::v8::internal::StepNext; // From StepAction enum
61using ::v8::internal::StepOut; // From StepAction enum
62using ::v8::internal::Vector;
Steve Blockd0582a62009-12-15 09:54:21 +000063using ::v8::internal::StrLength;
Steve Blocka7e24c12009-10-30 11:49:00 +000064
65// Size of temp buffer for formatting small strings.
66#define SMALL_STRING_BUFFER_SIZE 80
67
Steve Blocka7e24c12009-10-30 11:49:00 +000068// --- H e l p e r C l a s s e s
69
70
71// Helper class for creating a V8 enviromnent for running tests
72class DebugLocalContext {
73 public:
74 inline DebugLocalContext(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000075 v8::Isolate* isolate, v8::ExtensionConfiguration* extensions = 0,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000076 v8::Local<v8::ObjectTemplate> global_template =
77 v8::Local<v8::ObjectTemplate>(),
78 v8::Local<v8::Value> global_object = v8::Local<v8::Value>())
Ben Murdochb8a8cc12014-11-26 15:28:44 +000079 : scope_(isolate),
80 context_(v8::Context::New(isolate, extensions, global_template,
81 global_object)) {
82 context_->Enter();
83 }
84 inline DebugLocalContext(
Steve Blocka7e24c12009-10-30 11:49:00 +000085 v8::ExtensionConfiguration* extensions = 0,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000086 v8::Local<v8::ObjectTemplate> global_template =
87 v8::Local<v8::ObjectTemplate>(),
88 v8::Local<v8::Value> global_object = v8::Local<v8::Value>())
Ben Murdochb8a8cc12014-11-26 15:28:44 +000089 : scope_(CcTest::isolate()),
90 context_(v8::Context::New(CcTest::isolate(), extensions,
91 global_template, global_object)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000092 context_->Enter();
93 }
94 inline ~DebugLocalContext() {
95 context_->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +000096 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000097 inline v8::Local<v8::Context> context() { return context_; }
Steve Blocka7e24c12009-10-30 11:49:00 +000098 inline v8::Context* operator->() { return *context_; }
99 inline v8::Context* operator*() { return *context_; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000100 inline v8::Isolate* GetIsolate() { return context_->GetIsolate(); }
Steve Blocka7e24c12009-10-30 11:49:00 +0000101 inline bool IsReady() { return !context_.IsEmpty(); }
102 void ExposeDebug() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000103 v8::internal::Isolate* isolate =
104 reinterpret_cast<v8::internal::Isolate*>(context_->GetIsolate());
105 v8::internal::Factory* factory = isolate->factory();
Steve Blocka7e24c12009-10-30 11:49:00 +0000106 // Expose the debug context global object in the global object for testing.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000107 CHECK(isolate->debug()->Load());
108 Handle<v8::internal::Context> debug_context =
109 isolate->debug()->debug_context();
110 debug_context->set_security_token(
Steve Blocka7e24c12009-10-30 11:49:00 +0000111 v8::Utils::OpenHandle(*context_)->security_token());
112
113 Handle<JSGlobalProxy> global(Handle<JSGlobalProxy>::cast(
114 v8::Utils::OpenHandle(*context_->Global())));
115 Handle<v8::internal::String> debug_string =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000116 factory->InternalizeOneByteString(STATIC_CHAR_VECTOR("debug"));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000117 v8::internal::JSObject::SetOwnPropertyIgnoreAttributes(
118 global, debug_string, handle(debug_context->global_proxy()),
119 v8::internal::DONT_ENUM)
120 .Check();
Steve Blocka7e24c12009-10-30 11:49:00 +0000121 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000122
Steve Blocka7e24c12009-10-30 11:49:00 +0000123 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000124 v8::HandleScope scope_;
125 v8::Local<v8::Context> context_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000126};
127
128
129// --- H e l p e r F u n c t i o n s
130
Steve Blocka7e24c12009-10-30 11:49:00 +0000131// Compile and run the supplied source and return the requested function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000132static v8::Local<v8::Function> CompileFunction(v8::Isolate* isolate,
133 const char* source,
Steve Blocka7e24c12009-10-30 11:49:00 +0000134 const char* function_name) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000135 CompileRunChecked(isolate, source);
136 v8::Local<v8::String> name = v8_str(isolate, function_name);
137 v8::Local<v8::Context> context = isolate->GetCurrentContext();
138 v8::MaybeLocal<v8::Value> maybe_function =
139 context->Global()->Get(context, name);
140 return v8::Local<v8::Function>::Cast(maybe_function.ToLocalChecked());
141}
142
143
144// Compile and run the supplied source and return the requested function.
145static v8::Local<v8::Function> CompileFunction(DebugLocalContext* env,
146 const char* source,
147 const char* function_name) {
148 return CompileFunction(env->GetIsolate(), source, function_name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000149}
150
151
Steve Blocka7e24c12009-10-30 11:49:00 +0000152// Is there any debug info for the function?
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000153static bool HasDebugInfo(v8::Local<v8::Function> fun) {
154 Handle<v8::internal::JSFunction> f =
155 Handle<v8::internal::JSFunction>::cast(v8::Utils::OpenHandle(*fun));
Steve Blocka7e24c12009-10-30 11:49:00 +0000156 Handle<v8::internal::SharedFunctionInfo> shared(f->shared());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000157 return shared->HasDebugInfo();
Steve Blocka7e24c12009-10-30 11:49:00 +0000158}
159
160
161// Set a break point in a function and return the associated break point
162// number.
163static int SetBreakPoint(Handle<v8::internal::JSFunction> fun, int position) {
164 static int break_point = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000165 v8::internal::Isolate* isolate = fun->GetIsolate();
166 v8::internal::Debug* debug = isolate->debug();
Steve Block44f0eee2011-05-26 01:26:41 +0100167 debug->SetBreakPoint(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000168 fun,
169 Handle<Object>(v8::internal::Smi::FromInt(++break_point), isolate),
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100170 &position);
Steve Blocka7e24c12009-10-30 11:49:00 +0000171 return break_point;
172}
173
174
175// Set a break point in a function and return the associated break point
176// number.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000177static int SetBreakPoint(v8::Local<v8::Function> fun, int position) {
178 return SetBreakPoint(
179 i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*fun)), position);
Steve Blocka7e24c12009-10-30 11:49:00 +0000180}
181
182
183// Set a break point in a function using the Debug object and return the
184// associated break point number.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000185static int SetBreakPointFromJS(v8::Isolate* isolate,
186 const char* function_name,
Steve Blocka7e24c12009-10-30 11:49:00 +0000187 int line, int position) {
188 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000189 SNPrintF(buffer,
190 "debug.Debug.setBreakPoint(%s,%d,%d)",
191 function_name, line, position);
Steve Blocka7e24c12009-10-30 11:49:00 +0000192 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000193 v8::Local<v8::Value> value = CompileRunChecked(isolate, buffer.start());
194 return value->Int32Value(isolate->GetCurrentContext()).FromJust();
Steve Blocka7e24c12009-10-30 11:49:00 +0000195}
196
197
198// Set a break point in a script identified by id using the global Debug object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000199static int SetScriptBreakPointByIdFromJS(v8::Isolate* isolate, int script_id,
200 int line, int column) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000201 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
202 if (column >= 0) {
203 // Column specified set script break point on precise location.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000204 SNPrintF(buffer,
205 "debug.Debug.setScriptBreakPointById(%d,%d,%d)",
206 script_id, line, column);
Steve Blocka7e24c12009-10-30 11:49:00 +0000207 } else {
208 // Column not specified set script break point on line.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000209 SNPrintF(buffer,
210 "debug.Debug.setScriptBreakPointById(%d,%d)",
211 script_id, line);
Steve Blocka7e24c12009-10-30 11:49:00 +0000212 }
213 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
214 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000215 v8::TryCatch try_catch(isolate);
216 v8::Local<v8::Value> value = CompileRunChecked(isolate, buffer.start());
Steve Blocka7e24c12009-10-30 11:49:00 +0000217 CHECK(!try_catch.HasCaught());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000218 return value->Int32Value(isolate->GetCurrentContext()).FromJust();
Steve Blocka7e24c12009-10-30 11:49:00 +0000219 }
220}
221
222
223// Set a break point in a script identified by name using the global Debug
224// object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000225static int SetScriptBreakPointByNameFromJS(v8::Isolate* isolate,
226 const char* script_name, int line,
227 int column) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000228 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
229 if (column >= 0) {
230 // Column specified set script break point on precise location.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000231 SNPrintF(buffer,
232 "debug.Debug.setScriptBreakPointByName(\"%s\",%d,%d)",
233 script_name, line, column);
Steve Blocka7e24c12009-10-30 11:49:00 +0000234 } else {
235 // Column not specified set script break point on line.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000236 SNPrintF(buffer,
237 "debug.Debug.setScriptBreakPointByName(\"%s\",%d)",
238 script_name, line);
Steve Blocka7e24c12009-10-30 11:49:00 +0000239 }
240 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
241 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242 v8::TryCatch try_catch(isolate);
243 v8::Local<v8::Value> value = CompileRunChecked(isolate, buffer.start());
Steve Blocka7e24c12009-10-30 11:49:00 +0000244 CHECK(!try_catch.HasCaught());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000245 return value->Int32Value(isolate->GetCurrentContext()).FromJust();
Steve Blocka7e24c12009-10-30 11:49:00 +0000246 }
247}
248
249
250// Clear a break point.
251static void ClearBreakPoint(int break_point) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000252 v8::internal::Isolate* isolate = CcTest::i_isolate();
253 v8::internal::Debug* debug = isolate->debug();
Steve Block44f0eee2011-05-26 01:26:41 +0100254 debug->ClearBreakPoint(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000255 Handle<Object>(v8::internal::Smi::FromInt(break_point), isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +0000256}
257
258
259// Clear a break point using the global Debug object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000260static void ClearBreakPointFromJS(v8::Isolate* isolate,
261 int break_point_number) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000262 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000263 SNPrintF(buffer,
264 "debug.Debug.clearBreakPoint(%d)",
265 break_point_number);
Steve Blocka7e24c12009-10-30 11:49:00 +0000266 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000267 CompileRunChecked(isolate, buffer.start());
Steve Blocka7e24c12009-10-30 11:49:00 +0000268}
269
270
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000271static void EnableScriptBreakPointFromJS(v8::Isolate* isolate,
272 int break_point_number) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000273 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000274 SNPrintF(buffer,
275 "debug.Debug.enableScriptBreakPoint(%d)",
276 break_point_number);
Steve Blocka7e24c12009-10-30 11:49:00 +0000277 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000278 CompileRunChecked(isolate, buffer.start());
Steve Blocka7e24c12009-10-30 11:49:00 +0000279}
280
281
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000282static void DisableScriptBreakPointFromJS(v8::Isolate* isolate,
283 int break_point_number) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000284 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000285 SNPrintF(buffer,
286 "debug.Debug.disableScriptBreakPoint(%d)",
287 break_point_number);
Steve Blocka7e24c12009-10-30 11:49:00 +0000288 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000289 CompileRunChecked(isolate, buffer.start());
Steve Blocka7e24c12009-10-30 11:49:00 +0000290}
291
292
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000293static void ChangeScriptBreakPointConditionFromJS(v8::Isolate* isolate,
294 int break_point_number,
Steve Blocka7e24c12009-10-30 11:49:00 +0000295 const char* condition) {
296 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000297 SNPrintF(buffer,
298 "debug.Debug.changeScriptBreakPointCondition(%d, \"%s\")",
299 break_point_number, condition);
Steve Blocka7e24c12009-10-30 11:49:00 +0000300 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000301 CompileRunChecked(isolate, buffer.start());
Steve Blocka7e24c12009-10-30 11:49:00 +0000302}
303
304
Steve Blocka7e24c12009-10-30 11:49:00 +0000305// Change break on exception.
306static void ChangeBreakOnException(bool caught, bool uncaught) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000307 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
Steve Block44f0eee2011-05-26 01:26:41 +0100308 debug->ChangeBreakOnException(v8::internal::BreakException, caught);
309 debug->ChangeBreakOnException(v8::internal::BreakUncaughtException, uncaught);
Steve Blocka7e24c12009-10-30 11:49:00 +0000310}
311
312
313// Change break on exception using the global Debug object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000314static void ChangeBreakOnExceptionFromJS(v8::Isolate* isolate, bool caught,
315 bool uncaught) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000316 if (caught) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000317 CompileRunChecked(isolate, "debug.Debug.setBreakOnException()");
Steve Blocka7e24c12009-10-30 11:49:00 +0000318 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000319 CompileRunChecked(isolate, "debug.Debug.clearBreakOnException()");
Steve Blocka7e24c12009-10-30 11:49:00 +0000320 }
321 if (uncaught) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000322 CompileRunChecked(isolate, "debug.Debug.setBreakOnUncaughtException()");
Steve Blocka7e24c12009-10-30 11:49:00 +0000323 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000324 CompileRunChecked(isolate, "debug.Debug.clearBreakOnUncaughtException()");
Steve Blocka7e24c12009-10-30 11:49:00 +0000325 }
326}
327
328
329// Prepare to step to next break location.
330static void PrepareStep(StepAction step_action) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000331 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332 debug->PrepareStep(step_action);
Steve Blocka7e24c12009-10-30 11:49:00 +0000333}
334
335
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000336static void ClearStepping() { CcTest::i_isolate()->debug()->ClearStepping(); }
337
338
Steve Blocka7e24c12009-10-30 11:49:00 +0000339// This function is in namespace v8::internal to be friend with class
340// v8::internal::Debug.
341namespace v8 {
342namespace internal {
343
344// Collect the currently debugged functions.
345Handle<FixedArray> GetDebuggedFunctions() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000346 Debug* debug = CcTest::i_isolate()->debug();
Steve Block44f0eee2011-05-26 01:26:41 +0100347
348 v8::internal::DebugInfoListNode* node = debug->debug_info_list_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000349
350 // Find the number of debugged functions.
351 int count = 0;
352 while (node) {
353 count++;
354 node = node->next();
355 }
356
357 // Allocate array for the debugged functions
358 Handle<FixedArray> debugged_functions =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000359 CcTest::i_isolate()->factory()->NewFixedArray(count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000360
361 // Run through the debug info objects and collect all functions.
362 count = 0;
363 while (node) {
364 debugged_functions->set(count++, *node->debug_info());
365 node = node->next();
366 }
367
368 return debugged_functions;
369}
370
371
Steve Blocka7e24c12009-10-30 11:49:00 +0000372// Check that the debugger has been fully unloaded.
373void CheckDebuggerUnloaded(bool check_functions) {
374 // Check that the debugger context is cleared and that there is no debug
375 // information stored for the debugger.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000376 CHECK(CcTest::i_isolate()->debug()->debug_context().is_null());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000377 CHECK(!CcTest::i_isolate()->debug()->debug_info_list_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000378
379 // Collect garbage to ensure weak handles are cleared.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000380 CcTest::heap()->CollectAllGarbage();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000381 CcTest::heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
Steve Blocka7e24c12009-10-30 11:49:00 +0000382
383 // Iterate the head and check that there are no debugger related objects left.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000384 HeapIterator iterator(CcTest::heap());
Leon Clarked91b9f72010-01-27 17:25:45 +0000385 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000386 CHECK(!obj->IsDebugInfo());
387 CHECK(!obj->IsBreakPointInfo());
388
389 // If deep check of functions is requested check that no debug break code
390 // is left in all functions.
391 if (check_functions) {
392 if (obj->IsJSFunction()) {
393 JSFunction* fun = JSFunction::cast(obj);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000394 for (RelocIterator it(fun->shared()->code(),
395 RelocInfo::kDebugBreakSlotMask);
396 !it.done(); it.next()) {
397 CHECK(!it.rinfo()->IsPatchedDebugBreakSlotSequence());
Steve Blocka7e24c12009-10-30 11:49:00 +0000398 }
399 }
400 }
401 }
402}
403
404
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000405} // namespace internal
406} // namespace v8
Steve Blocka7e24c12009-10-30 11:49:00 +0000407
408
409// Check that the debugger has been fully unloaded.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000410static void CheckDebuggerUnloaded(v8::Isolate* isolate,
411 bool check_functions = false) {
Leon Clarkee46be812010-01-19 14:06:41 +0000412 // Let debugger to unload itself synchronously
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000413 v8::Debug::ProcessDebugMessages(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +0000414
Steve Blocka7e24c12009-10-30 11:49:00 +0000415 v8::internal::CheckDebuggerUnloaded(check_functions);
416}
417
418
Steve Blocka7e24c12009-10-30 11:49:00 +0000419// --- D e b u g E v e n t H a n d l e r s
420// ---
421// --- The different tests uses a number of debug event handlers.
422// ---
423
424
Ben Murdochb0fe1622011-05-05 13:52:32 +0100425// Source for the JavaScript function which picks out the function
426// name of a frame.
Steve Blocka7e24c12009-10-30 11:49:00 +0000427const char* frame_function_name_source =
Ben Murdochb0fe1622011-05-05 13:52:32 +0100428 "function frame_function_name(exec_state, frame_number) {"
429 " return exec_state.frame(frame_number).func().name();"
Steve Blocka7e24c12009-10-30 11:49:00 +0000430 "}";
431v8::Local<v8::Function> frame_function_name;
432
433
Ben Murdochb0fe1622011-05-05 13:52:32 +0100434// Source for the JavaScript function which pick out the name of the
435// first argument of a frame.
436const char* frame_argument_name_source =
437 "function frame_argument_name(exec_state, frame_number) {"
438 " return exec_state.frame(frame_number).argumentName(0);"
439 "}";
440v8::Local<v8::Function> frame_argument_name;
441
442
443// Source for the JavaScript function which pick out the value of the
444// first argument of a frame.
445const char* frame_argument_value_source =
446 "function frame_argument_value(exec_state, frame_number) {"
447 " return exec_state.frame(frame_number).argumentValue(0).value_;"
448 "}";
449v8::Local<v8::Function> frame_argument_value;
450
451
452// Source for the JavaScript function which pick out the name of the
453// first argument of a frame.
454const char* frame_local_name_source =
455 "function frame_local_name(exec_state, frame_number) {"
456 " return exec_state.frame(frame_number).localName(0);"
457 "}";
458v8::Local<v8::Function> frame_local_name;
459
460
461// Source for the JavaScript function which pick out the value of the
462// first argument of a frame.
463const char* frame_local_value_source =
464 "function frame_local_value(exec_state, frame_number) {"
465 " return exec_state.frame(frame_number).localValue(0).value_;"
466 "}";
467v8::Local<v8::Function> frame_local_value;
468
469
470// Source for the JavaScript function which picks out the source line for the
Steve Blocka7e24c12009-10-30 11:49:00 +0000471// top frame.
472const char* frame_source_line_source =
473 "function frame_source_line(exec_state) {"
474 " return exec_state.frame(0).sourceLine();"
475 "}";
476v8::Local<v8::Function> frame_source_line;
477
478
Ben Murdochb0fe1622011-05-05 13:52:32 +0100479// Source for the JavaScript function which picks out the source column for the
Steve Blocka7e24c12009-10-30 11:49:00 +0000480// top frame.
481const char* frame_source_column_source =
482 "function frame_source_column(exec_state) {"
483 " return exec_state.frame(0).sourceColumn();"
484 "}";
485v8::Local<v8::Function> frame_source_column;
486
487
Ben Murdochb0fe1622011-05-05 13:52:32 +0100488// Source for the JavaScript function which picks out the script name for the
Steve Blocka7e24c12009-10-30 11:49:00 +0000489// top frame.
490const char* frame_script_name_source =
491 "function frame_script_name(exec_state) {"
492 " return exec_state.frame(0).func().script().name();"
493 "}";
494v8::Local<v8::Function> frame_script_name;
495
496
Ben Murdochb0fe1622011-05-05 13:52:32 +0100497// Source for the JavaScript function which returns the number of frames.
Steve Blocka7e24c12009-10-30 11:49:00 +0000498static const char* frame_count_source =
499 "function frame_count(exec_state) {"
500 " return exec_state.frameCount();"
501 "}";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000502v8::Local<v8::Function> frame_count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000503
504
505// Global variable to store the last function hit - used by some tests.
506char last_function_hit[80];
507
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000508// Global variable to store the name for last script hit - used by some tests.
Steve Blocka7e24c12009-10-30 11:49:00 +0000509char last_script_name_hit[80];
Steve Blocka7e24c12009-10-30 11:49:00 +0000510
511// Global variables to store the last source position - used by some tests.
512int last_source_line = -1;
513int last_source_column = -1;
514
515// Debug event handler which counts the break points which have been hit.
516int break_point_hit_count = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000517int break_point_hit_count_deoptimize = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000518static void DebugEventBreakPointHitCount(
519 const v8::Debug::EventDetails& event_details) {
520 v8::DebugEvent event = event_details.GetEvent();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000521 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
522 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000523 v8::internal::Isolate* isolate = CcTest::i_isolate();
524 Debug* debug = isolate->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000525 // When hitting a debug event listener there must be a break set.
Steve Block44f0eee2011-05-26 01:26:41 +0100526 CHECK_NE(debug->break_id(), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000527
528 // Count the number of breaks.
529 if (event == v8::Break) {
530 break_point_hit_count++;
531 if (!frame_function_name.IsEmpty()) {
532 // Get the name of the function.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100533 const int argc = 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000534 v8::Local<v8::Value> argv[argc] = {
535 exec_state, v8::Integer::New(CcTest::isolate(), 0)};
536 v8::Local<v8::Value> result =
537 frame_function_name->Call(context, exec_state, argc, argv)
538 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000539 if (result->IsUndefined()) {
540 last_function_hit[0] = '\0';
541 } else {
542 CHECK(result->IsString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000543 v8::Local<v8::String> function_name(result.As<v8::String>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000544 function_name->WriteUtf8(last_function_hit);
Steve Blocka7e24c12009-10-30 11:49:00 +0000545 }
546 }
547
548 if (!frame_source_line.IsEmpty()) {
549 // Get the source line.
550 const int argc = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000551 v8::Local<v8::Value> argv[argc] = {exec_state};
552 v8::Local<v8::Value> result =
553 frame_source_line->Call(context, exec_state, argc, argv)
554 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000555 CHECK(result->IsNumber());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000556 last_source_line = result->Int32Value(context).FromJust();
Steve Blocka7e24c12009-10-30 11:49:00 +0000557 }
558
559 if (!frame_source_column.IsEmpty()) {
560 // Get the source column.
561 const int argc = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000562 v8::Local<v8::Value> argv[argc] = {exec_state};
563 v8::Local<v8::Value> result =
564 frame_source_column->Call(context, exec_state, argc, argv)
565 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000566 CHECK(result->IsNumber());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000567 last_source_column = result->Int32Value(context).FromJust();
Steve Blocka7e24c12009-10-30 11:49:00 +0000568 }
569
570 if (!frame_script_name.IsEmpty()) {
571 // Get the script name of the function script.
572 const int argc = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000573 v8::Local<v8::Value> argv[argc] = {exec_state};
574 v8::Local<v8::Value> result =
575 frame_script_name->Call(context, exec_state, argc, argv)
576 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000577 if (result->IsUndefined()) {
578 last_script_name_hit[0] = '\0';
579 } else {
580 CHECK(result->IsString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000581 v8::Local<v8::String> script_name(result.As<v8::String>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000582 script_name->WriteUtf8(last_script_name_hit);
Steve Blocka7e24c12009-10-30 11:49:00 +0000583 }
584 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000585
586 // Perform a full deoptimization when the specified number of
587 // breaks have been hit.
588 if (break_point_hit_count == break_point_hit_count_deoptimize) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000589 i::Deoptimizer::DeoptimizeAll(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +0000590 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000591 }
592}
593
594
595// Debug event handler which counts a number of events and collects the stack
596// height if there is a function compiled for that.
597int exception_hit_count = 0;
598int uncaught_exception_hit_count = 0;
599int last_js_stack_height = -1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000600v8::Local<v8::Function> debug_event_listener_callback;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000601int debug_event_listener_callback_result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000602
603static void DebugEventCounterClear() {
604 break_point_hit_count = 0;
605 exception_hit_count = 0;
606 uncaught_exception_hit_count = 0;
607}
608
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000609static void DebugEventCounter(
610 const v8::Debug::EventDetails& event_details) {
611 v8::DebugEvent event = event_details.GetEvent();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000612 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
613 v8::Local<v8::Object> event_data = event_details.GetEventData();
614 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000615 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
Steve Block44f0eee2011-05-26 01:26:41 +0100616
Steve Blocka7e24c12009-10-30 11:49:00 +0000617 // When hitting a debug event listener there must be a break set.
Steve Block44f0eee2011-05-26 01:26:41 +0100618 CHECK_NE(debug->break_id(), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000619
620 // Count the number of breaks.
621 if (event == v8::Break) {
622 break_point_hit_count++;
623 } else if (event == v8::Exception) {
624 exception_hit_count++;
625
626 // Check whether the exception was uncaught.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000627 v8::Local<v8::String> fun_name = v8_str(CcTest::isolate(), "uncaught");
628 v8::Local<v8::Function> fun = v8::Local<v8::Function>::Cast(
629 event_data->Get(context, fun_name).ToLocalChecked());
630 v8::Local<v8::Value> result =
631 fun->Call(context, event_data, 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000632 if (result->IsTrue()) {
633 uncaught_exception_hit_count++;
634 }
635 }
636
637 // Collect the JavsScript stack height if the function frame_count is
638 // compiled.
639 if (!frame_count.IsEmpty()) {
640 static const int kArgc = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000641 v8::Local<v8::Value> argv[kArgc] = {exec_state};
Steve Blocka7e24c12009-10-30 11:49:00 +0000642 // Using exec_state as receiver is just to have a receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000643 v8::Local<v8::Value> result =
644 frame_count->Call(context, exec_state, kArgc, argv).ToLocalChecked();
645 last_js_stack_height = result->Int32Value(context).FromJust();
Steve Blocka7e24c12009-10-30 11:49:00 +0000646 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000647
648 // Run callback from DebugEventListener and check the result.
649 if (!debug_event_listener_callback.IsEmpty()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000650 v8::Local<v8::Value> result =
651 debug_event_listener_callback->Call(context, event_data, 0, NULL)
652 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000653 CHECK(!result.IsEmpty());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000654 CHECK_EQ(debug_event_listener_callback_result,
655 result->Int32Value(context).FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000656 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000657}
658
659
660// Debug event handler which evaluates a number of expressions when a break
661// point is hit. Each evaluated expression is compared with an expected value.
662// For this debug event handler to work the following two global varaibles
663// must be initialized.
664// checks: An array of expressions and expected results
665// evaluate_check_function: A JavaScript function (see below)
666
667// Structure for holding checks to do.
668struct EvaluateCheck {
669 const char* expr; // An expression to evaluate when a break point is hit.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000670 v8::Local<v8::Value> expected; // The expected result.
Steve Blocka7e24c12009-10-30 11:49:00 +0000671};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000672
673
Steve Blocka7e24c12009-10-30 11:49:00 +0000674// Array of checks to do.
675struct EvaluateCheck* checks = NULL;
676// Source for The JavaScript function which can do the evaluation when a break
677// point is hit.
678const char* evaluate_check_source =
679 "function evaluate_check(exec_state, expr, expected) {"
680 " return exec_state.frame(0).evaluate(expr).value() === expected;"
681 "}";
682v8::Local<v8::Function> evaluate_check_function;
683
684// The actual debug event described by the longer comment above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000685static void DebugEventEvaluate(
686 const v8::Debug::EventDetails& event_details) {
687 v8::DebugEvent event = event_details.GetEvent();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000688 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
689 v8::Isolate* isolate = CcTest::isolate();
690 v8::Local<v8::Context> context = isolate->GetCurrentContext();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000691 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000692 // When hitting a debug event listener there must be a break set.
Steve Block44f0eee2011-05-26 01:26:41 +0100693 CHECK_NE(debug->break_id(), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000694
695 if (event == v8::Break) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000696 break_point_hit_count++;
Steve Blocka7e24c12009-10-30 11:49:00 +0000697 for (int i = 0; checks[i].expr != NULL; i++) {
698 const int argc = 3;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000699 v8::Local<v8::String> string = v8_str(isolate, checks[i].expr);
700 v8::Local<v8::Value> argv[argc] = {exec_state, string,
701 checks[i].expected};
702 v8::Local<v8::Value> result =
703 evaluate_check_function->Call(context, exec_state, argc, argv)
704 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000705 if (!result->IsTrue()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400706 v8::String::Utf8Value utf8(checks[i].expected);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000707 V8_Fatal(__FILE__, __LINE__, "%s != %s", checks[i].expr, *utf8);
Steve Blocka7e24c12009-10-30 11:49:00 +0000708 }
709 }
710 }
711}
712
713
714// This debug event listener removes a breakpoint in a function
715int debug_event_remove_break_point = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000716static void DebugEventRemoveBreakPoint(
717 const v8::Debug::EventDetails& event_details) {
718 v8::DebugEvent event = event_details.GetEvent();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000719 v8::Local<v8::Value> data = event_details.GetCallbackData();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000720 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000721 // When hitting a debug event listener there must be a break set.
Steve Block44f0eee2011-05-26 01:26:41 +0100722 CHECK_NE(debug->break_id(), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000723
724 if (event == v8::Break) {
725 break_point_hit_count++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100726 CHECK(data->IsFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +0000727 ClearBreakPoint(debug_event_remove_break_point);
728 }
729}
730
731
732// Debug event handler which counts break points hit and performs a step
733// afterwards.
734StepAction step_action = StepIn; // Step action to perform when stepping.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000735static void DebugEventStep(
736 const v8::Debug::EventDetails& event_details) {
737 v8::DebugEvent event = event_details.GetEvent();
738 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000739 // When hitting a debug event listener there must be a break set.
Steve Block44f0eee2011-05-26 01:26:41 +0100740 CHECK_NE(debug->break_id(), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000741
742 if (event == v8::Break) {
743 break_point_hit_count++;
744 PrepareStep(step_action);
745 }
746}
747
748
749// Debug event handler which counts break points hit and performs a step
750// afterwards. For each call the expected function is checked.
751// For this debug event handler to work the following two global varaibles
752// must be initialized.
753// expected_step_sequence: An array of the expected function call sequence.
754// frame_function_name: A JavaScript function (see below).
755
756// String containing the expected function call sequence. Note: this only works
757// if functions have name length of one.
758const char* expected_step_sequence = NULL;
759
760// The actual debug event described by the longer comment above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000761static void DebugEventStepSequence(
762 const v8::Debug::EventDetails& event_details) {
763 v8::DebugEvent event = event_details.GetEvent();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000764 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000765 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000766 // When hitting a debug event listener there must be a break set.
Steve Block44f0eee2011-05-26 01:26:41 +0100767 CHECK_NE(debug->break_id(), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000768
769 if (event == v8::Break || event == v8::Exception) {
770 // Check that the current function is the expected.
771 CHECK(break_point_hit_count <
Steve Blockd0582a62009-12-15 09:54:21 +0000772 StrLength(expected_step_sequence));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100773 const int argc = 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000774 v8::Local<v8::Value> argv[argc] = {exec_state,
775 v8::Integer::New(CcTest::isolate(), 0)};
776 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
777 v8::Local<v8::Value> result =
778 frame_function_name->Call(context, exec_state, argc, argv)
779 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000780 CHECK(result->IsString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000781 v8::String::Utf8Value function_name(
782 result->ToString(context).ToLocalChecked());
Steve Blockd0582a62009-12-15 09:54:21 +0000783 CHECK_EQ(1, StrLength(*function_name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000784 CHECK_EQ((*function_name)[0],
785 expected_step_sequence[break_point_hit_count]);
786
787 // Perform step.
788 break_point_hit_count++;
789 PrepareStep(step_action);
790 }
791}
792
793
794// Debug event handler which performs a garbage collection.
795static void DebugEventBreakPointCollectGarbage(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000796 const v8::Debug::EventDetails& event_details) {
797 v8::DebugEvent event = event_details.GetEvent();
798 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000799 // When hitting a debug event listener there must be a break set.
Steve Block44f0eee2011-05-26 01:26:41 +0100800 CHECK_NE(debug->break_id(), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000801
802 // Perform a garbage collection when break point is hit and continue. Based
803 // on the number of break points hit either scavenge or mark compact
804 // collector is used.
805 if (event == v8::Break) {
806 break_point_hit_count++;
807 if (break_point_hit_count % 2 == 0) {
808 // Scavenge.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000809 CcTest::heap()->CollectGarbage(v8::internal::NEW_SPACE);
Steve Blocka7e24c12009-10-30 11:49:00 +0000810 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100811 // Mark sweep compact.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000812 CcTest::heap()->CollectAllGarbage();
Steve Blocka7e24c12009-10-30 11:49:00 +0000813 }
814 }
815}
816
817
818// Debug event handler which re-issues a debug break and calls the garbage
819// collector to have the heap verified.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000820static void DebugEventBreak(
821 const v8::Debug::EventDetails& event_details) {
822 v8::DebugEvent event = event_details.GetEvent();
823 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000824 // When hitting a debug event listener there must be a break set.
Steve Block44f0eee2011-05-26 01:26:41 +0100825 CHECK_NE(debug->break_id(), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000826
827 if (event == v8::Break) {
828 // Count the number of breaks.
829 break_point_hit_count++;
830
831 // Run the garbage collector to enforce heap verification if option
832 // --verify-heap is set.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000833 CcTest::heap()->CollectGarbage(v8::internal::NEW_SPACE);
Steve Blocka7e24c12009-10-30 11:49:00 +0000834
835 // Set the break flag again to come back here as soon as possible.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000836 v8::Debug::DebugBreak(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000837 }
838}
839
840
Steve Blockd0582a62009-12-15 09:54:21 +0000841// Debug event handler which re-issues a debug break until a limit has been
842// reached.
843int max_break_point_hit_count = 0;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800844bool terminate_after_max_break_point_hit = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000845static void DebugEventBreakMax(
846 const v8::Debug::EventDetails& event_details) {
847 v8::DebugEvent event = event_details.GetEvent();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000848 v8::Isolate* v8_isolate = CcTest::isolate();
849 v8::internal::Isolate* isolate = CcTest::i_isolate();
850 v8::internal::Debug* debug = isolate->debug();
Steve Blockd0582a62009-12-15 09:54:21 +0000851 // When hitting a debug event listener there must be a break set.
Steve Block44f0eee2011-05-26 01:26:41 +0100852 CHECK_NE(debug->break_id(), 0);
Steve Blockd0582a62009-12-15 09:54:21 +0000853
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800854 if (event == v8::Break) {
855 if (break_point_hit_count < max_break_point_hit_count) {
856 // Count the number of breaks.
857 break_point_hit_count++;
Steve Blockd0582a62009-12-15 09:54:21 +0000858
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800859 // Set the break flag again to come back here as soon as possible.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000860 v8::Debug::DebugBreak(v8_isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000861
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800862 } else if (terminate_after_max_break_point_hit) {
863 // Terminate execution after the last break if requested.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000864 v8_isolate->TerminateExecution();
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800865 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000866
867 // Perform a full deoptimization when the specified number of
868 // breaks have been hit.
869 if (break_point_hit_count == break_point_hit_count_deoptimize) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000870 i::Deoptimizer::DeoptimizeAll(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000871 }
Steve Blockd0582a62009-12-15 09:54:21 +0000872 }
873}
874
875
Steve Blocka7e24c12009-10-30 11:49:00 +0000876// --- M e s s a g e C a l l b a c k
877
878
879// Message callback which counts the number of messages.
880int message_callback_count = 0;
881
882static void MessageCallbackCountClear() {
883 message_callback_count = 0;
884}
885
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000886static void MessageCallbackCount(v8::Local<v8::Message> message,
887 v8::Local<v8::Value> data) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000888 message_callback_count++;
889}
890
891
892// --- T h e A c t u a l T e s t s
893
Steve Blocka7e24c12009-10-30 11:49:00 +0000894// Test that the debug info in the VM is in sync with the functions being
895// debugged.
896TEST(DebugInfo) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000897 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000898 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000899 // Create a couple of functions for the test.
900 v8::Local<v8::Function> foo =
901 CompileFunction(&env, "function foo(){}", "foo");
902 v8::Local<v8::Function> bar =
903 CompileFunction(&env, "function bar(){}", "bar");
904 // Initially no functions are debugged.
905 CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
906 CHECK(!HasDebugInfo(foo));
907 CHECK(!HasDebugInfo(bar));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000908 EnableDebugger(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000909 // One function (foo) is debugged.
910 int bp1 = SetBreakPoint(foo, 0);
911 CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
912 CHECK(HasDebugInfo(foo));
913 CHECK(!HasDebugInfo(bar));
914 // Two functions are debugged.
915 int bp2 = SetBreakPoint(bar, 0);
916 CHECK_EQ(2, v8::internal::GetDebuggedFunctions()->length());
917 CHECK(HasDebugInfo(foo));
918 CHECK(HasDebugInfo(bar));
919 // One function (bar) is debugged.
920 ClearBreakPoint(bp1);
921 CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
922 CHECK(!HasDebugInfo(foo));
923 CHECK(HasDebugInfo(bar));
924 // No functions are debugged.
925 ClearBreakPoint(bp2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000926 DisableDebugger(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000927 CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
928 CHECK(!HasDebugInfo(foo));
929 CHECK(!HasDebugInfo(bar));
930}
931
932
933// Test that a break point can be set at an IC store location.
934TEST(BreakPointICStore) {
935 break_point_hit_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000936 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000937 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000938
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000939 v8::Debug::SetDebugEventListener(env->GetIsolate(),
940 DebugEventBreakPointHitCount);
941 v8::Local<v8::Function> foo =
942 CompileFunction(&env, "function foo(){bar=0;}", "foo");
Steve Blocka7e24c12009-10-30 11:49:00 +0000943
944 // Run without breakpoints.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000945 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000946 CHECK_EQ(0, break_point_hit_count);
947
948 // Run with breakpoint
949 int bp = SetBreakPoint(foo, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000950 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000951 CHECK_EQ(1, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000952 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000953 CHECK_EQ(2, break_point_hit_count);
954
955 // Run without breakpoints.
956 ClearBreakPoint(bp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000957 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000958 CHECK_EQ(2, break_point_hit_count);
959
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000960 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
961 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000962}
963
964
965// Test that a break point can be set at an IC load location.
966TEST(BreakPointICLoad) {
967 break_point_hit_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000968 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000969 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000970 v8::Debug::SetDebugEventListener(env->GetIsolate(),
971 DebugEventBreakPointHitCount);
972
973 CompileRunChecked(env->GetIsolate(), "bar=1");
974 v8::Local<v8::Function> foo =
975 CompileFunction(&env, "function foo(){var x=bar;}", "foo");
Steve Blocka7e24c12009-10-30 11:49:00 +0000976
977 // Run without breakpoints.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000978 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000979 CHECK_EQ(0, break_point_hit_count);
980
Steve Block44f0eee2011-05-26 01:26:41 +0100981 // Run with breakpoint.
Steve Blocka7e24c12009-10-30 11:49:00 +0000982 int bp = SetBreakPoint(foo, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000983 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000984 CHECK_EQ(1, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000985 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000986 CHECK_EQ(2, break_point_hit_count);
987
988 // Run without breakpoints.
989 ClearBreakPoint(bp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000990 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000991 CHECK_EQ(2, break_point_hit_count);
992
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000993 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
994 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000995}
996
997
998// Test that a break point can be set at an IC call location.
999TEST(BreakPointICCall) {
1000 break_point_hit_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001001 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001002 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001003 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1004 DebugEventBreakPointHitCount);
1005 CompileRunChecked(env->GetIsolate(), "function bar(){}");
1006 v8::Local<v8::Function> foo =
1007 CompileFunction(&env, "function foo(){bar();}", "foo");
Steve Blocka7e24c12009-10-30 11:49:00 +00001008
1009 // Run without breakpoints.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001010 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001011 CHECK_EQ(0, break_point_hit_count);
1012
Steve Block44f0eee2011-05-26 01:26:41 +01001013 // Run with breakpoint
Steve Blocka7e24c12009-10-30 11:49:00 +00001014 int bp = SetBreakPoint(foo, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001015 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001016 CHECK_EQ(1, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001017 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001018 CHECK_EQ(2, break_point_hit_count);
1019
1020 // Run without breakpoints.
1021 ClearBreakPoint(bp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001022 foo->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001023 CHECK_EQ(2, break_point_hit_count);
1024
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001025 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1026 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001027}
1028
1029
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001030// Test that a break point can be set at an IC call location and survive a GC.
1031TEST(BreakPointICCallWithGC) {
1032 break_point_hit_count = 0;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001033 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001034 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001035 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1036 DebugEventBreakPointCollectGarbage);
1037 CompileRunChecked(env->GetIsolate(), "function bar(){return 1;}");
1038 v8::Local<v8::Function> foo =
1039 CompileFunction(&env, "function foo(){return bar();}", "foo");
1040 v8::Local<v8::Context> context = env.context();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001041
1042 // Run without breakpoints.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001043 CHECK_EQ(1, foo->Call(context, env->Global(), 0, NULL)
1044 .ToLocalChecked()
1045 ->Int32Value(context)
1046 .FromJust());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001047 CHECK_EQ(0, break_point_hit_count);
1048
1049 // Run with breakpoint.
1050 int bp = SetBreakPoint(foo, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001051 CHECK_EQ(1, foo->Call(context, env->Global(), 0, NULL)
1052 .ToLocalChecked()
1053 ->Int32Value(context)
1054 .FromJust());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001055 CHECK_EQ(1, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001056 CHECK_EQ(1, foo->Call(context, env->Global(), 0, NULL)
1057 .ToLocalChecked()
1058 ->Int32Value(context)
1059 .FromJust());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001060 CHECK_EQ(2, break_point_hit_count);
1061
1062 // Run without breakpoints.
1063 ClearBreakPoint(bp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001064 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001065 CHECK_EQ(2, break_point_hit_count);
1066
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001067 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1068 CheckDebuggerUnloaded(env->GetIsolate());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001069}
1070
1071
1072// Test that a break point can be set at an IC call location and survive a GC.
1073TEST(BreakPointConstructCallWithGC) {
1074 break_point_hit_count = 0;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001075 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001076 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001077 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1078 DebugEventBreakPointCollectGarbage);
1079 CompileRunChecked(env->GetIsolate(), "function bar(){ this.x = 1;}");
1080 v8::Local<v8::Function> foo =
1081 CompileFunction(&env, "function foo(){return new bar(1).x;}", "foo");
1082 v8::Local<v8::Context> context = env.context();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001083
1084 // Run without breakpoints.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001085 CHECK_EQ(1, foo->Call(context, env->Global(), 0, NULL)
1086 .ToLocalChecked()
1087 ->Int32Value(context)
1088 .FromJust());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001089 CHECK_EQ(0, break_point_hit_count);
1090
1091 // Run with breakpoint.
1092 int bp = SetBreakPoint(foo, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001093 CHECK_EQ(1, foo->Call(context, env->Global(), 0, NULL)
1094 .ToLocalChecked()
1095 ->Int32Value(context)
1096 .FromJust());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001097 CHECK_EQ(1, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001098 CHECK_EQ(1, foo->Call(context, env->Global(), 0, NULL)
1099 .ToLocalChecked()
1100 ->Int32Value(context)
1101 .FromJust());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001102 CHECK_EQ(2, break_point_hit_count);
1103
1104 // Run without breakpoints.
1105 ClearBreakPoint(bp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001106 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001107 CHECK_EQ(2, break_point_hit_count);
1108
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001109 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1110 CheckDebuggerUnloaded(env->GetIsolate());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001111}
1112
1113
Steve Blocka7e24c12009-10-30 11:49:00 +00001114// Test that a break point can be set at a return store location.
1115TEST(BreakPointReturn) {
1116 break_point_hit_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001117 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001118 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001119
1120 // Create a functions for checking the source line and column when hitting
1121 // a break point.
1122 frame_source_line = CompileFunction(&env,
1123 frame_source_line_source,
1124 "frame_source_line");
1125 frame_source_column = CompileFunction(&env,
1126 frame_source_column_source,
1127 "frame_source_column");
1128
1129
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001130 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1131 DebugEventBreakPointHitCount);
1132 v8::Local<v8::Function> foo =
1133 CompileFunction(&env, "function foo(){}", "foo");
1134 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00001135
1136 // Run without breakpoints.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001137 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001138 CHECK_EQ(0, break_point_hit_count);
1139
1140 // Run with breakpoint
1141 int bp = SetBreakPoint(foo, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001142 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001143 CHECK_EQ(1, break_point_hit_count);
1144 CHECK_EQ(0, last_source_line);
Ben Murdochbb769b22010-08-11 14:56:33 +01001145 CHECK_EQ(15, last_source_column);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001146 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001147 CHECK_EQ(2, break_point_hit_count);
1148 CHECK_EQ(0, last_source_line);
Ben Murdochbb769b22010-08-11 14:56:33 +01001149 CHECK_EQ(15, last_source_column);
Steve Blocka7e24c12009-10-30 11:49:00 +00001150
1151 // Run without breakpoints.
1152 ClearBreakPoint(bp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001153 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001154 CHECK_EQ(2, break_point_hit_count);
1155
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001156 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1157 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001158}
1159
1160
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001161static void CallWithBreakPoints(v8::Local<v8::Context> context,
1162 v8::Local<v8::Object> recv,
Steve Blocka7e24c12009-10-30 11:49:00 +00001163 v8::Local<v8::Function> f,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001164 int break_point_count, int call_count) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001165 break_point_hit_count = 0;
1166 for (int i = 0; i < call_count; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001167 f->Call(context, recv, 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001168 CHECK_EQ((i + 1) * break_point_count, break_point_hit_count);
1169 }
1170}
1171
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001172
Steve Blocka7e24c12009-10-30 11:49:00 +00001173// Test GC during break point processing.
1174TEST(GCDuringBreakPointProcessing) {
1175 break_point_hit_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001176 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001177 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001178 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00001179
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001180 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1181 DebugEventBreakPointCollectGarbage);
Steve Blocka7e24c12009-10-30 11:49:00 +00001182 v8::Local<v8::Function> foo;
1183
1184 // Test IC store break point with garbage collection.
1185 foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1186 SetBreakPoint(foo, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001187 CallWithBreakPoints(context, env->Global(), foo, 1, 10);
Steve Blocka7e24c12009-10-30 11:49:00 +00001188
1189 // Test IC load break point with garbage collection.
1190 foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1191 SetBreakPoint(foo, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001192 CallWithBreakPoints(context, env->Global(), foo, 1, 10);
Steve Blocka7e24c12009-10-30 11:49:00 +00001193
1194 // Test IC call break point with garbage collection.
1195 foo = CompileFunction(&env, "function bar(){};function foo(){bar();}", "foo");
1196 SetBreakPoint(foo, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001197 CallWithBreakPoints(context, env->Global(), foo, 1, 10);
Steve Blocka7e24c12009-10-30 11:49:00 +00001198
1199 // Test return break point with garbage collection.
1200 foo = CompileFunction(&env, "function foo(){}", "foo");
1201 SetBreakPoint(foo, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001202 CallWithBreakPoints(context, env->Global(), foo, 1, 25);
Steve Blocka7e24c12009-10-30 11:49:00 +00001203
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001204 // Test debug break slot break point with garbage collection.
1205 foo = CompileFunction(&env, "function foo(){var a;}", "foo");
1206 SetBreakPoint(foo, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001207 CallWithBreakPoints(context, env->Global(), foo, 1, 25);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001208
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001209 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1210 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001211}
1212
1213
1214// Call the function three times with different garbage collections in between
1215// and make sure that the break point survives.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001216static void CallAndGC(v8::Local<v8::Context> context,
1217 v8::Local<v8::Object> recv, v8::Local<v8::Function> f) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001218 break_point_hit_count = 0;
1219
1220 for (int i = 0; i < 3; i++) {
1221 // Call function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001222 f->Call(context, recv, 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001223 CHECK_EQ(1 + i * 3, break_point_hit_count);
1224
1225 // Scavenge and call function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001226 CcTest::heap()->CollectGarbage(v8::internal::NEW_SPACE);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001227 f->Call(context, recv, 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001228 CHECK_EQ(2 + i * 3, break_point_hit_count);
1229
1230 // Mark sweep (and perhaps compact) and call function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001231 CcTest::heap()->CollectAllGarbage();
1232 f->Call(context, recv, 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001233 CHECK_EQ(3 + i * 3, break_point_hit_count);
1234 }
1235}
1236
1237
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001238// Test that a break point can be set at a return store location.
1239TEST(BreakPointSurviveGC) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001240 break_point_hit_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001241 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001242 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001243 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00001244
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001245 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1246 DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00001247 v8::Local<v8::Function> foo;
1248
1249 // Test IC store break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001250 {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001251 CompileFunction(&env, "function foo(){}", "foo");
Ben Murdochbb769b22010-08-11 14:56:33 +01001252 foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1253 SetBreakPoint(foo, 0);
1254 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001255 CallAndGC(context, env->Global(), foo);
Steve Blocka7e24c12009-10-30 11:49:00 +00001256
1257 // Test IC load break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001258 {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001259 CompileFunction(&env, "function foo(){}", "foo");
Ben Murdochbb769b22010-08-11 14:56:33 +01001260 foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1261 SetBreakPoint(foo, 0);
1262 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001263 CallAndGC(context, env->Global(), foo);
Steve Blocka7e24c12009-10-30 11:49:00 +00001264
1265 // Test IC call break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001266 {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001267 CompileFunction(&env, "function foo(){}", "foo");
Ben Murdochbb769b22010-08-11 14:56:33 +01001268 foo = CompileFunction(&env,
1269 "function bar(){};function foo(){bar();}",
1270 "foo");
1271 SetBreakPoint(foo, 0);
1272 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001273 CallAndGC(context, env->Global(), foo);
Steve Blocka7e24c12009-10-30 11:49:00 +00001274
1275 // Test return break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001276 {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001277 CompileFunction(&env, "function foo(){}", "foo");
Ben Murdochbb769b22010-08-11 14:56:33 +01001278 foo = CompileFunction(&env, "function foo(){}", "foo");
1279 SetBreakPoint(foo, 0);
1280 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001281 CallAndGC(context, env->Global(), foo);
Ben Murdochbb769b22010-08-11 14:56:33 +01001282
1283 // Test non IC break point with garbage collection.
1284 {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001285 CompileFunction(&env, "function foo(){}", "foo");
Ben Murdochbb769b22010-08-11 14:56:33 +01001286 foo = CompileFunction(&env, "function foo(){var bar=0;}", "foo");
1287 SetBreakPoint(foo, 0);
1288 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001289 CallAndGC(context, env->Global(), foo);
Ben Murdochbb769b22010-08-11 14:56:33 +01001290
Steve Blocka7e24c12009-10-30 11:49:00 +00001291
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001292 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1293 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001294}
1295
1296
1297// Test that break points can be set using the global Debug object.
1298TEST(BreakPointThroughJavaScript) {
1299 break_point_hit_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001300 DebugLocalContext env;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001301 v8::Isolate* isolate = env->GetIsolate();
1302 v8::HandleScope scope(isolate);
1303 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00001304 env.ExposeDebug();
1305
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001306 v8::Debug::SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
1307 CompileRunChecked(isolate, "function bar(){}");
1308 CompileFunction(isolate, "function foo(){bar();bar();}", "foo");
1309 // 012345678901234567890
1310 // 1 2
Steve Blocka7e24c12009-10-30 11:49:00 +00001311 // Break points are set at position 3 and 9
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001312 v8::Local<v8::String> source = v8_str(env->GetIsolate(), "foo()");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001313 v8::Local<v8::Script> foo =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001314 v8::Script::Compile(context, source).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001315
Steve Blocka7e24c12009-10-30 11:49:00 +00001316 CHECK_EQ(0, break_point_hit_count);
1317
1318 // Run with one breakpoint
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001319 int bp1 = SetBreakPointFromJS(env->GetIsolate(), "foo", 0, 3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001320 foo->Run(context).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001321 CHECK_EQ(1, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001322 foo->Run(context).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001323 CHECK_EQ(2, break_point_hit_count);
1324
1325 // Run with two breakpoints
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001326 int bp2 = SetBreakPointFromJS(env->GetIsolate(), "foo", 0, 9);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001327 foo->Run(context).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001328 CHECK_EQ(4, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001329 foo->Run(context).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001330 CHECK_EQ(6, break_point_hit_count);
1331
1332 // Run with one breakpoint
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001333 ClearBreakPointFromJS(env->GetIsolate(), bp2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001334 foo->Run(context).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001335 CHECK_EQ(7, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001336 foo->Run(context).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001337 CHECK_EQ(8, break_point_hit_count);
1338
1339 // Run without breakpoints.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001340 ClearBreakPointFromJS(env->GetIsolate(), bp1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001341 foo->Run(context).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001342 CHECK_EQ(8, break_point_hit_count);
1343
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001344 v8::Debug::SetDebugEventListener(isolate, nullptr);
1345 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001346
1347 // Make sure that the break point numbers are consecutive.
1348 CHECK_EQ(1, bp1);
1349 CHECK_EQ(2, bp2);
1350}
1351
1352
1353// Test that break points on scripts identified by name can be set using the
1354// global Debug object.
1355TEST(ScriptBreakPointByNameThroughJavaScript) {
1356 break_point_hit_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001357 DebugLocalContext env;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001358 v8::Isolate* isolate = env->GetIsolate();
1359 v8::HandleScope scope(isolate);
1360 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00001361 env.ExposeDebug();
1362
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001363 v8::Debug::SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00001364
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001365 v8::Local<v8::String> script = v8_str(isolate,
1366 "function f() {\n"
1367 " function h() {\n"
1368 " a = 0; // line 2\n"
1369 " }\n"
1370 " b = 1; // line 4\n"
1371 " return h();\n"
1372 "}\n"
1373 "\n"
1374 "function g() {\n"
1375 " function h() {\n"
1376 " a = 0;\n"
1377 " }\n"
1378 " b = 2; // line 12\n"
1379 " h();\n"
1380 " b = 3; // line 14\n"
1381 " f(); // line 15\n"
1382 "}");
Steve Blocka7e24c12009-10-30 11:49:00 +00001383
1384 // Compile the script and get the two functions.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001385 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(isolate, "test"));
1386 v8::Script::Compile(context, script, &origin)
1387 .ToLocalChecked()
1388 ->Run(context)
1389 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001390 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001391 env->Global()->Get(context, v8_str(isolate, "f")).ToLocalChecked());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001392 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001393 env->Global()->Get(context, v8_str(isolate, "g")).ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00001394
1395 // Call f and g without break points.
1396 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001397 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001398 CHECK_EQ(0, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001399 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001400 CHECK_EQ(0, break_point_hit_count);
1401
1402 // Call f and g with break point on line 12.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001403 int sbp1 = SetScriptBreakPointByNameFromJS(isolate, "test", 12, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001404 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001405 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001406 CHECK_EQ(0, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001407 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001408 CHECK_EQ(1, break_point_hit_count);
1409
1410 // Remove the break point again.
1411 break_point_hit_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001412 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001413 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001414 CHECK_EQ(0, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001415 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001416 CHECK_EQ(0, break_point_hit_count);
1417
1418 // Call f and g with break point on line 2.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001419 int sbp2 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 2, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001420 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001421 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001422 CHECK_EQ(1, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001423 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001424 CHECK_EQ(2, break_point_hit_count);
1425
1426 // Call f and g with break point on line 2, 4, 12, 14 and 15.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001427 int sbp3 = SetScriptBreakPointByNameFromJS(isolate, "test", 4, 0);
1428 int sbp4 = SetScriptBreakPointByNameFromJS(isolate, "test", 12, 0);
1429 int sbp5 = SetScriptBreakPointByNameFromJS(isolate, "test", 14, 0);
1430 int sbp6 = SetScriptBreakPointByNameFromJS(isolate, "test", 15, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001431 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001432 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001433 CHECK_EQ(2, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001434 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001435 CHECK_EQ(7, break_point_hit_count);
1436
1437 // Remove all the break points again.
1438 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001439 ClearBreakPointFromJS(isolate, sbp2);
1440 ClearBreakPointFromJS(isolate, sbp3);
1441 ClearBreakPointFromJS(isolate, sbp4);
1442 ClearBreakPointFromJS(isolate, sbp5);
1443 ClearBreakPointFromJS(isolate, sbp6);
1444 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001445 CHECK_EQ(0, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001446 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001447 CHECK_EQ(0, break_point_hit_count);
1448
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001449 v8::Debug::SetDebugEventListener(isolate, nullptr);
1450 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001451
1452 // Make sure that the break point numbers are consecutive.
1453 CHECK_EQ(1, sbp1);
1454 CHECK_EQ(2, sbp2);
1455 CHECK_EQ(3, sbp3);
1456 CHECK_EQ(4, sbp4);
1457 CHECK_EQ(5, sbp5);
1458 CHECK_EQ(6, sbp6);
1459}
1460
1461
1462TEST(ScriptBreakPointByIdThroughJavaScript) {
1463 break_point_hit_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001464 DebugLocalContext env;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001465 v8::Isolate* isolate = env->GetIsolate();
1466 v8::HandleScope scope(isolate);
1467 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00001468 env.ExposeDebug();
1469
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001470 v8::Debug::SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00001471
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001472 v8::Local<v8::String> source = v8_str(isolate,
1473 "function f() {\n"
1474 " function h() {\n"
1475 " a = 0; // line 2\n"
1476 " }\n"
1477 " b = 1; // line 4\n"
1478 " return h();\n"
1479 "}\n"
1480 "\n"
1481 "function g() {\n"
1482 " function h() {\n"
1483 " a = 0;\n"
1484 " }\n"
1485 " b = 2; // line 12\n"
1486 " h();\n"
1487 " b = 3; // line 14\n"
1488 " f(); // line 15\n"
1489 "}");
Steve Blocka7e24c12009-10-30 11:49:00 +00001490
1491 // Compile the script and get the two functions.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001492 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(isolate, "test"));
1493 v8::Local<v8::Script> script =
1494 v8::Script::Compile(context, source, &origin).ToLocalChecked();
1495 script->Run(context).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001496 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001497 env->Global()->Get(context, v8_str(isolate, "f")).ToLocalChecked());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001498 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001499 env->Global()->Get(context, v8_str(isolate, "g")).ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00001500
1501 // Get the script id knowing that internally it is a 32 integer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001502 int script_id = script->GetUnboundScript()->GetId();
Steve Blocka7e24c12009-10-30 11:49:00 +00001503
1504 // Call f and g without break points.
1505 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001506 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001507 CHECK_EQ(0, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001508 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001509 CHECK_EQ(0, break_point_hit_count);
1510
1511 // Call f and g with break point on line 12.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001512 int sbp1 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 12, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001513 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001514 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001515 CHECK_EQ(0, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001516 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001517 CHECK_EQ(1, break_point_hit_count);
1518
1519 // Remove the break point again.
1520 break_point_hit_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001521 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001522 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001523 CHECK_EQ(0, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001524 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001525 CHECK_EQ(0, break_point_hit_count);
1526
1527 // Call f and g with break point on line 2.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001528 int sbp2 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 2, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001529 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001530 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001531 CHECK_EQ(1, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001532 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001533 CHECK_EQ(2, break_point_hit_count);
1534
1535 // Call f and g with break point on line 2, 4, 12, 14 and 15.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001536 int sbp3 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 4, 0);
1537 int sbp4 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 12, 0);
1538 int sbp5 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 14, 0);
1539 int sbp6 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 15, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001540 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001541 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001542 CHECK_EQ(2, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001543 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001544 CHECK_EQ(7, break_point_hit_count);
1545
1546 // Remove all the break points again.
1547 break_point_hit_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001548 ClearBreakPointFromJS(env->GetIsolate(), sbp2);
1549 ClearBreakPointFromJS(env->GetIsolate(), sbp3);
1550 ClearBreakPointFromJS(env->GetIsolate(), sbp4);
1551 ClearBreakPointFromJS(env->GetIsolate(), sbp5);
1552 ClearBreakPointFromJS(env->GetIsolate(), sbp6);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001553 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001554 CHECK_EQ(0, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001555 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001556 CHECK_EQ(0, break_point_hit_count);
1557
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001558 v8::Debug::SetDebugEventListener(isolate, nullptr);
1559 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001560
1561 // Make sure that the break point numbers are consecutive.
1562 CHECK_EQ(1, sbp1);
1563 CHECK_EQ(2, sbp2);
1564 CHECK_EQ(3, sbp3);
1565 CHECK_EQ(4, sbp4);
1566 CHECK_EQ(5, sbp5);
1567 CHECK_EQ(6, sbp6);
1568}
1569
1570
1571// Test conditional script break points.
1572TEST(EnableDisableScriptBreakPoint) {
1573 break_point_hit_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001574 DebugLocalContext env;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001575 v8::Isolate* isolate = env->GetIsolate();
1576 v8::HandleScope scope(isolate);
1577 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00001578 env.ExposeDebug();
1579
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001580 v8::Debug::SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00001581
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001582 v8::Local<v8::String> script = v8_str(isolate,
1583 "function f() {\n"
1584 " a = 0; // line 1\n"
1585 "};");
Steve Blocka7e24c12009-10-30 11:49:00 +00001586
1587 // Compile the script and get function f.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001588 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(isolate, "test"));
1589 v8::Script::Compile(context, script, &origin)
1590 .ToLocalChecked()
1591 ->Run(context)
1592 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001593 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001594 env->Global()->Get(context, v8_str(isolate, "f")).ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00001595
1596 // Set script break point on line 1 (in function f).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001597 int sbp = SetScriptBreakPointByNameFromJS(isolate, "test", 1, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001598
1599 // Call f while enabeling and disabling the script break point.
1600 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001601 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001602 CHECK_EQ(1, break_point_hit_count);
1603
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001604 DisableScriptBreakPointFromJS(isolate, sbp);
1605 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001606 CHECK_EQ(1, break_point_hit_count);
1607
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001608 EnableScriptBreakPointFromJS(isolate, sbp);
1609 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001610 CHECK_EQ(2, break_point_hit_count);
1611
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001612 DisableScriptBreakPointFromJS(isolate, sbp);
1613 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001614 CHECK_EQ(2, break_point_hit_count);
1615
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001616 // Reload the script and get f again checking that the disabling survives.
1617 v8::Script::Compile(context, script, &origin)
1618 .ToLocalChecked()
1619 ->Run(context)
1620 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001621 f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001622 env->Global()->Get(context, v8_str(isolate, "f")).ToLocalChecked());
1623 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001624 CHECK_EQ(2, break_point_hit_count);
1625
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001626 EnableScriptBreakPointFromJS(isolate, sbp);
1627 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001628 CHECK_EQ(3, break_point_hit_count);
1629
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001630 v8::Debug::SetDebugEventListener(isolate, nullptr);
1631 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001632}
1633
1634
1635// Test conditional script break points.
1636TEST(ConditionalScriptBreakPoint) {
1637 break_point_hit_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001638 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001639 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001640 env.ExposeDebug();
1641
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001642 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1643 DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00001644
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001645 v8::Local<v8::String> script = v8_str(env->GetIsolate(),
1646 "count = 0;\n"
1647 "function f() {\n"
1648 " g(count++); // line 2\n"
1649 "};\n"
1650 "function g(x) {\n"
1651 " var a=x; // line 5\n"
1652 "};");
Steve Blocka7e24c12009-10-30 11:49:00 +00001653
1654 // Compile the script and get function f.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001655 v8::Local<v8::Context> context = env.context();
1656 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(env->GetIsolate(), "test"));
1657 v8::Script::Compile(context, script, &origin)
1658 .ToLocalChecked()
1659 ->Run(context)
1660 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001661 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001662 env->Global()
1663 ->Get(context, v8_str(env->GetIsolate(), "f"))
1664 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00001665
1666 // Set script break point on line 5 (in function g).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001667 int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 5, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001668
1669 // Call f with different conditions on the script break point.
1670 break_point_hit_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001671 ChangeScriptBreakPointConditionFromJS(env->GetIsolate(), sbp1, "false");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001672 f->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001673 CHECK_EQ(0, break_point_hit_count);
1674
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001675 ChangeScriptBreakPointConditionFromJS(env->GetIsolate(), sbp1, "true");
Steve Blocka7e24c12009-10-30 11:49:00 +00001676 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001677 f->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001678 CHECK_EQ(1, break_point_hit_count);
1679
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001680 ChangeScriptBreakPointConditionFromJS(env->GetIsolate(), sbp1, "x % 2 == 0");
Steve Blocka7e24c12009-10-30 11:49:00 +00001681 break_point_hit_count = 0;
1682 for (int i = 0; i < 10; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001683 f->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001684 }
1685 CHECK_EQ(5, break_point_hit_count);
1686
1687 // Reload the script and get f again checking that the condition survives.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001688 v8::Script::Compile(context, script, &origin)
1689 .ToLocalChecked()
1690 ->Run(context)
1691 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001692 f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001693 env->Global()
1694 ->Get(context, v8_str(env->GetIsolate(), "f"))
1695 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00001696
1697 break_point_hit_count = 0;
1698 for (int i = 0; i < 10; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001699 f->Call(env.context(), env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001700 }
1701 CHECK_EQ(5, break_point_hit_count);
1702
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001703 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1704 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001705}
1706
1707
Steve Blocka7e24c12009-10-30 11:49:00 +00001708// Test that script break points survive when a script is reloaded.
1709TEST(ScriptBreakPointReload) {
1710 break_point_hit_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001711 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001712 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001713 env.ExposeDebug();
1714
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001715 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1716 DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00001717
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001718 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00001719 v8::Local<v8::Function> f;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001720 v8::Local<v8::String> script = v8_str(env->GetIsolate(),
1721 "function f() {\n"
1722 " function h() {\n"
1723 " a = 0; // line 2\n"
1724 " }\n"
1725 " b = 1; // line 4\n"
1726 " return h();\n"
1727 "}");
Steve Blocka7e24c12009-10-30 11:49:00 +00001728
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001729 v8::ScriptOrigin origin_1 = v8::ScriptOrigin(v8_str(env->GetIsolate(), "1"));
1730 v8::ScriptOrigin origin_2 = v8::ScriptOrigin(v8_str(env->GetIsolate(), "2"));
Steve Blocka7e24c12009-10-30 11:49:00 +00001731
1732 // Set a script break point before the script is loaded.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001733 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "1", 2, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001734
1735 // Compile the script and get the function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001736 v8::Script::Compile(context, script, &origin_1)
1737 .ToLocalChecked()
1738 ->Run(context)
1739 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001740 f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001741 env->Global()
1742 ->Get(context, v8_str(env->GetIsolate(), "f"))
1743 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00001744
1745 // Call f and check that the script break point is active.
1746 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001747 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001748 CHECK_EQ(1, break_point_hit_count);
1749
1750 // Compile the script again with a different script data and get the
1751 // function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001752 v8::Script::Compile(context, script, &origin_2)
1753 .ToLocalChecked()
1754 ->Run(context)
1755 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001756 f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001757 env->Global()
1758 ->Get(context, v8_str(env->GetIsolate(), "f"))
1759 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00001760
1761 // Call f and check that no break points are set.
1762 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001763 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001764 CHECK_EQ(0, break_point_hit_count);
1765
1766 // Compile the script again and get the function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001767 v8::Script::Compile(context, script, &origin_1)
1768 .ToLocalChecked()
1769 ->Run(context)
1770 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001771 f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001772 env->Global()
1773 ->Get(context, v8_str(env->GetIsolate(), "f"))
1774 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00001775
1776 // Call f and check that the script break point is active.
1777 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001778 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001779 CHECK_EQ(1, break_point_hit_count);
1780
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001781 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1782 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001783}
1784
1785
1786// Test when several scripts has the same script data
1787TEST(ScriptBreakPointMultiple) {
1788 break_point_hit_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001789 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001790 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001791 env.ExposeDebug();
1792
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001793 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1794 DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00001795
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001796 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00001797 v8::Local<v8::Function> f;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001798 v8::Local<v8::String> script_f = v8_str(env->GetIsolate(),
1799 "function f() {\n"
1800 " a = 0; // line 1\n"
1801 "}");
Steve Blocka7e24c12009-10-30 11:49:00 +00001802
1803 v8::Local<v8::Function> g;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001804 v8::Local<v8::String> script_g = v8_str(env->GetIsolate(),
1805 "function g() {\n"
1806 " b = 0; // line 1\n"
1807 "}");
Steve Blocka7e24c12009-10-30 11:49:00 +00001808
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001809 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(env->GetIsolate(), "test"));
Steve Blocka7e24c12009-10-30 11:49:00 +00001810
1811 // Set a script break point before the scripts are loaded.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001812 int sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001813
1814 // Compile the scripts with same script data and get the functions.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001815 v8::Script::Compile(context, script_f, &origin)
1816 .ToLocalChecked()
1817 ->Run(context)
1818 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001819 f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001820 env->Global()
1821 ->Get(context, v8_str(env->GetIsolate(), "f"))
1822 .ToLocalChecked());
1823 v8::Script::Compile(context, script_g, &origin)
1824 .ToLocalChecked()
1825 ->Run(context)
1826 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001827 g = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001828 env->Global()
1829 ->Get(context, v8_str(env->GetIsolate(), "g"))
1830 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00001831
1832 // Call f and g and check that the script break point is active.
1833 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001834 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001835 CHECK_EQ(1, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001836 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001837 CHECK_EQ(2, break_point_hit_count);
1838
1839 // Clear the script break point.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001840 ClearBreakPointFromJS(env->GetIsolate(), sbp);
Steve Blocka7e24c12009-10-30 11:49:00 +00001841
1842 // Call f and g and check that the script break point is no longer active.
1843 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001844 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001845 CHECK_EQ(0, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001846 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001847 CHECK_EQ(0, break_point_hit_count);
1848
1849 // Set script break point with the scripts loaded.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001850 sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001851
1852 // Call f and g and check that the script break point is active.
1853 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001854 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001855 CHECK_EQ(1, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001856 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001857 CHECK_EQ(2, break_point_hit_count);
1858
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001859 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1860 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001861}
1862
1863
1864// Test the script origin which has both name and line offset.
1865TEST(ScriptBreakPointLineOffset) {
1866 break_point_hit_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001867 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001868 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001869 env.ExposeDebug();
1870
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001871 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1872 DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00001873
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001874 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00001875 v8::Local<v8::Function> f;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001876 v8::Local<v8::String> script =
1877 v8_str(env->GetIsolate(),
1878 "function f() {\n"
1879 " a = 0; // line 8 as this script has line offset 7\n"
1880 " b = 0; // line 9 as this script has line offset 7\n"
1881 "}");
Steve Blocka7e24c12009-10-30 11:49:00 +00001882
1883 // Create script origin both name and line offset.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001884 v8::ScriptOrigin origin(v8_str(env->GetIsolate(), "test.html"),
1885 v8::Integer::New(env->GetIsolate(), 7));
Steve Blocka7e24c12009-10-30 11:49:00 +00001886
1887 // Set two script break points before the script is loaded.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001888 int sbp1 =
1889 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 8, 0);
1890 int sbp2 =
1891 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 9, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001892
1893 // Compile the script and get the function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001894 v8::Script::Compile(context, script, &origin)
1895 .ToLocalChecked()
1896 ->Run(context)
1897 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001898 f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001899 env->Global()
1900 ->Get(context, v8_str(env->GetIsolate(), "f"))
1901 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00001902
1903 // Call f and check that the script break point is active.
1904 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001905 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001906 CHECK_EQ(2, break_point_hit_count);
1907
1908 // Clear the script break points.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001909 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
1910 ClearBreakPointFromJS(env->GetIsolate(), sbp2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001911
1912 // Call f and check that no script break points are active.
1913 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001914 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001915 CHECK_EQ(0, break_point_hit_count);
1916
1917 // Set a script break point with the script loaded.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001918 sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 9, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001919
1920 // Call f and check that the script break point is active.
1921 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001922 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001923 CHECK_EQ(1, break_point_hit_count);
1924
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001925 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
1926 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001927}
1928
1929
1930// Test script break points set on lines.
1931TEST(ScriptBreakPointLine) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001932 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001933 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001934 env.ExposeDebug();
1935
1936 // Create a function for checking the function when hitting a break point.
1937 frame_function_name = CompileFunction(&env,
1938 frame_function_name_source,
1939 "frame_function_name");
1940
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001941 v8::Debug::SetDebugEventListener(env->GetIsolate(),
1942 DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00001943
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001944 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00001945 v8::Local<v8::Function> f;
1946 v8::Local<v8::Function> g;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001947 v8::Local<v8::String> script =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001948 v8_str(env->GetIsolate(),
1949 "a = 0 // line 0\n"
1950 "function f() {\n"
1951 " a = 1; // line 2\n"
1952 "}\n"
1953 " a = 2; // line 4\n"
1954 " /* xx */ function g() { // line 5\n"
1955 " function h() { // line 6\n"
1956 " a = 3; // line 7\n"
1957 " }\n"
1958 " h(); // line 9\n"
1959 " a = 4; // line 10\n"
1960 " }\n"
1961 " a=5; // line 12");
Steve Blocka7e24c12009-10-30 11:49:00 +00001962
1963 // Set a couple script break point before the script is loaded.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001964 int sbp1 =
1965 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 0, -1);
1966 int sbp2 =
1967 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 1, -1);
1968 int sbp3 =
1969 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 5, -1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001970
1971 // Compile the script and get the function.
1972 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001973 v8::ScriptOrigin origin(v8_str(env->GetIsolate(), "test.html"),
1974 v8::Integer::New(env->GetIsolate(), 0));
1975 v8::Script::Compile(context, script, &origin)
1976 .ToLocalChecked()
1977 ->Run(context)
1978 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001979 f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001980 env->Global()
1981 ->Get(context, v8_str(env->GetIsolate(), "f"))
1982 .ToLocalChecked());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001983 g = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001984 env->Global()
1985 ->Get(context, v8_str(env->GetIsolate(), "g"))
1986 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00001987
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001988 // Check that a break point was hit when the script was run.
Steve Blocka7e24c12009-10-30 11:49:00 +00001989 CHECK_EQ(1, break_point_hit_count);
Steve Blockd0582a62009-12-15 09:54:21 +00001990 CHECK_EQ(0, StrLength(last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00001991
1992 // Call f and check that the script break point.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001993 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001994 CHECK_EQ(2, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001995 CHECK_EQ(0, strcmp("f", last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00001996
1997 // Call g and check that the script break point.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001998 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001999 CHECK_EQ(3, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002000 CHECK_EQ(0, strcmp("g", last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00002001
2002 // Clear the script break point on g and set one on h.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002003 ClearBreakPointFromJS(env->GetIsolate(), sbp3);
2004 int sbp4 =
2005 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 6, -1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002006
2007 // Call g and check that the script break point in h is hit.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002008 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002009 CHECK_EQ(4, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002010 CHECK_EQ(0, strcmp("h", last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00002011
2012 // Clear break points in f and h. Set a new one in the script between
2013 // functions f and g and test that there is no break points in f and g any
2014 // more.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002015 ClearBreakPointFromJS(env->GetIsolate(), sbp2);
2016 ClearBreakPointFromJS(env->GetIsolate(), sbp4);
2017 int sbp5 =
2018 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 4, -1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002019 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002020 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
2021 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002022 CHECK_EQ(0, break_point_hit_count);
2023
2024 // Reload the script which should hit two break points.
2025 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002026 v8::Script::Compile(context, script, &origin)
2027 .ToLocalChecked()
2028 ->Run(context)
2029 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002030 CHECK_EQ(2, break_point_hit_count);
Steve Blockd0582a62009-12-15 09:54:21 +00002031 CHECK_EQ(0, StrLength(last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00002032
2033 // Set a break point in the code after the last function decleration.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002034 int sbp6 =
2035 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 12, -1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002036
2037 // Reload the script which should hit three break points.
2038 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002039 v8::Script::Compile(context, script, &origin)
2040 .ToLocalChecked()
2041 ->Run(context)
2042 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002043 CHECK_EQ(3, break_point_hit_count);
Steve Blockd0582a62009-12-15 09:54:21 +00002044 CHECK_EQ(0, StrLength(last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00002045
2046 // Clear the last break points, and reload the script which should not hit any
2047 // break points.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002048 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
2049 ClearBreakPointFromJS(env->GetIsolate(), sbp5);
2050 ClearBreakPointFromJS(env->GetIsolate(), sbp6);
Steve Blocka7e24c12009-10-30 11:49:00 +00002051 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002052 v8::Script::Compile(context, script, &origin)
2053 .ToLocalChecked()
2054 ->Run(context)
2055 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002056 CHECK_EQ(0, break_point_hit_count);
2057
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002058 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2059 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002060}
2061
2062
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002063// Test top level script break points set on lines.
2064TEST(ScriptBreakPointLineTopLevel) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002065 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002066 v8::HandleScope scope(env->GetIsolate());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002067 env.ExposeDebug();
2068
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002069 v8::Debug::SetDebugEventListener(env->GetIsolate(),
2070 DebugEventBreakPointHitCount);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002071
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002072 v8::Local<v8::Context> context = env.context();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002073 v8::Local<v8::String> script =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002074 v8_str(env->GetIsolate(),
2075 "function f() {\n"
2076 " a = 1; // line 1\n"
2077 "}\n"
2078 "a = 2; // line 3\n");
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002079 v8::Local<v8::Function> f;
2080 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002081 v8::HandleScope scope(env->GetIsolate());
2082 CompileRunWithOrigin(script, "test.html");
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002083 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002084 f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002085 env->Global()
2086 ->Get(context, v8_str(env->GetIsolate(), "f"))
2087 .ToLocalChecked());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002088
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002089 CcTest::heap()->CollectAllGarbage();
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002090
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002091 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 3, -1);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002092
2093 // Call f and check that there was no break points.
2094 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002095 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002096 CHECK_EQ(0, break_point_hit_count);
2097
2098 // Recompile and run script and check that break point was hit.
2099 break_point_hit_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002100 CompileRunWithOrigin(script, "test.html");
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002101 CHECK_EQ(1, break_point_hit_count);
2102
2103 // Call f and check that there are still no break points.
2104 break_point_hit_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002105 f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002106 env->Global()
2107 ->Get(context, v8_str(env->GetIsolate(), "f"))
2108 .ToLocalChecked());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002109 CHECK_EQ(0, break_point_hit_count);
2110
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002111 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2112 CheckDebuggerUnloaded(env->GetIsolate());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002113}
2114
2115
Steve Block8defd9f2010-07-08 12:39:36 +01002116// Test that it is possible to add and remove break points in a top level
2117// function which has no references but has not been collected yet.
2118TEST(ScriptBreakPointTopLevelCrash) {
Steve Block8defd9f2010-07-08 12:39:36 +01002119 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002120 v8::HandleScope scope(env->GetIsolate());
Steve Block8defd9f2010-07-08 12:39:36 +01002121 env.ExposeDebug();
2122
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002123 v8::Debug::SetDebugEventListener(env->GetIsolate(),
2124 DebugEventBreakPointHitCount);
Steve Block8defd9f2010-07-08 12:39:36 +01002125
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002126 v8::Local<v8::String> script_source = v8_str(env->GetIsolate(),
2127 "function f() {\n"
2128 " return 0;\n"
2129 "}\n"
2130 "f()");
Steve Block8defd9f2010-07-08 12:39:36 +01002131
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002132 int sbp1 =
2133 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 3, -1);
Steve Block8defd9f2010-07-08 12:39:36 +01002134 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002135 v8::HandleScope scope(env->GetIsolate());
Steve Block8defd9f2010-07-08 12:39:36 +01002136 break_point_hit_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002137 CompileRunWithOrigin(script_source, "test.html");
Steve Block8defd9f2010-07-08 12:39:36 +01002138 CHECK_EQ(1, break_point_hit_count);
2139 }
2140
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002141 int sbp2 =
2142 SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 3, -1);
2143 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
2144 ClearBreakPointFromJS(env->GetIsolate(), sbp2);
Steve Block8defd9f2010-07-08 12:39:36 +01002145
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002146 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2147 CheckDebuggerUnloaded(env->GetIsolate());
Steve Block8defd9f2010-07-08 12:39:36 +01002148}
2149
2150
Steve Blocka7e24c12009-10-30 11:49:00 +00002151// Test that it is possible to remove the last break point for a function
2152// inside the break handling of that break point.
2153TEST(RemoveBreakPointInBreak) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002154 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002155 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002156
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002157 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00002158 v8::Local<v8::Function> foo =
2159 CompileFunction(&env, "function foo(){a=1;}", "foo");
Steve Blocka7e24c12009-10-30 11:49:00 +00002160
2161 // Register the debug event listener pasing the function
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002162 v8::Debug::SetDebugEventListener(env->GetIsolate(),
2163 DebugEventRemoveBreakPoint, foo);
2164
2165 debug_event_remove_break_point = SetBreakPoint(foo, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002166
2167 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002168 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002169 CHECK_EQ(1, break_point_hit_count);
2170
2171 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002172 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002173 CHECK_EQ(0, break_point_hit_count);
2174
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002175 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2176 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002177}
2178
2179
2180// Test that the debugger statement causes a break.
2181TEST(DebuggerStatement) {
2182 break_point_hit_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00002183 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002184 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002185 v8::Debug::SetDebugEventListener(env->GetIsolate(),
2186 DebugEventBreakPointHitCount);
2187 v8::Local<v8::Context> context = env.context();
2188 v8::Script::Compile(context,
2189 v8_str(env->GetIsolate(), "function bar(){debugger}"))
2190 .ToLocalChecked()
2191 ->Run(context)
2192 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002193 v8::Script::Compile(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002194 context, v8_str(env->GetIsolate(), "function foo(){debugger;debugger;}"))
2195 .ToLocalChecked()
2196 ->Run(context)
2197 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002198 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002199 env->Global()
2200 ->Get(context, v8_str(env->GetIsolate(), "foo"))
2201 .ToLocalChecked());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002202 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002203 env->Global()
2204 ->Get(context, v8_str(env->GetIsolate(), "bar"))
2205 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00002206
2207 // Run function with debugger statement
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002208 bar->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002209 CHECK_EQ(1, break_point_hit_count);
2210
2211 // Run function with two debugger statement
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002212 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002213 CHECK_EQ(3, break_point_hit_count);
2214
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002215 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2216 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002217}
2218
2219
Steve Block8defd9f2010-07-08 12:39:36 +01002220// Test setting a breakpoint on the debugger statement.
Leon Clarke4515c472010-02-03 11:58:03 +00002221TEST(DebuggerStatementBreakpoint) {
2222 break_point_hit_count = 0;
Leon Clarke4515c472010-02-03 11:58:03 +00002223 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002224 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002225 v8::Local<v8::Context> context = env.context();
2226 v8::Debug::SetDebugEventListener(env->GetIsolate(),
2227 DebugEventBreakPointHitCount);
2228 v8::Script::Compile(context,
2229 v8_str(env->GetIsolate(), "function foo(){debugger;}"))
2230 .ToLocalChecked()
2231 ->Run(context)
2232 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002233 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002234 env->Global()
2235 ->Get(context, v8_str(env->GetIsolate(), "foo"))
2236 .ToLocalChecked());
Leon Clarke4515c472010-02-03 11:58:03 +00002237
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002238 // The debugger statement triggers breakpoint hit
2239 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Leon Clarke4515c472010-02-03 11:58:03 +00002240 CHECK_EQ(1, break_point_hit_count);
2241
2242 int bp = SetBreakPoint(foo, 0);
2243
2244 // Set breakpoint does not duplicate hits
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002245 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Leon Clarke4515c472010-02-03 11:58:03 +00002246 CHECK_EQ(2, break_point_hit_count);
2247
2248 ClearBreakPoint(bp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002249 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2250 CheckDebuggerUnloaded(env->GetIsolate());
Leon Clarke4515c472010-02-03 11:58:03 +00002251}
2252
2253
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002254// Test that the evaluation of expressions when a break point is hit generates
Steve Blocka7e24c12009-10-30 11:49:00 +00002255// the correct results.
2256TEST(DebugEvaluate) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002257 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002258 v8::Isolate* isolate = env->GetIsolate();
2259 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002260 env.ExposeDebug();
2261
2262 // Create a function for checking the evaluation when hitting a break point.
2263 evaluate_check_function = CompileFunction(&env,
2264 evaluate_check_source,
2265 "evaluate_check");
2266 // Register the debug event listener
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002267 v8::Debug::SetDebugEventListener(isolate, DebugEventEvaluate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002268
2269 // Different expected vaules of x and a when in a break point (u = undefined,
2270 // d = Hello, world!).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002271 struct EvaluateCheck checks_uu[] = {{"x", v8::Undefined(isolate)},
2272 {"a", v8::Undefined(isolate)},
2273 {NULL, v8::Local<v8::Value>()}};
Steve Blocka7e24c12009-10-30 11:49:00 +00002274 struct EvaluateCheck checks_hu[] = {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002275 {"x", v8_str(env->GetIsolate(), "Hello, world!")},
2276 {"a", v8::Undefined(isolate)},
2277 {NULL, v8::Local<v8::Value>()}};
Steve Blocka7e24c12009-10-30 11:49:00 +00002278 struct EvaluateCheck checks_hh[] = {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002279 {"x", v8_str(env->GetIsolate(), "Hello, world!")},
2280 {"a", v8_str(env->GetIsolate(), "Hello, world!")},
2281 {NULL, v8::Local<v8::Value>()}};
Steve Blocka7e24c12009-10-30 11:49:00 +00002282
2283 // Simple test function. The "y=0" is in the function foo to provide a break
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002284 // location. For "y=0" the "y" is at position 15 in the foo function
Steve Blocka7e24c12009-10-30 11:49:00 +00002285 // therefore setting breakpoint at position 15 will break at "y=0" and
2286 // setting it higher will break after.
2287 v8::Local<v8::Function> foo = CompileFunction(&env,
2288 "function foo(x) {"
2289 " var a;"
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002290 " y=0;" // To ensure break location 1.
Steve Blocka7e24c12009-10-30 11:49:00 +00002291 " a=x;"
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002292 " y=0;" // To ensure break location 2.
Steve Blocka7e24c12009-10-30 11:49:00 +00002293 "}",
2294 "foo");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002295 const int foo_break_position_1 = 15;
2296 const int foo_break_position_2 = 29;
Steve Blocka7e24c12009-10-30 11:49:00 +00002297
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002298 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00002299 // Arguments with one parameter "Hello, world!"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002300 v8::Local<v8::Value> argv_foo[1] = {
2301 v8_str(env->GetIsolate(), "Hello, world!")};
Steve Blocka7e24c12009-10-30 11:49:00 +00002302
2303 // Call foo with breakpoint set before a=x and undefined as parameter.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002304 int bp = SetBreakPoint(foo, foo_break_position_1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002305 checks = checks_uu;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002306 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002307
2308 // Call foo with breakpoint set before a=x and parameter "Hello, world!".
2309 checks = checks_hu;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002310 foo->Call(context, env->Global(), 1, argv_foo).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002311
2312 // Call foo with breakpoint set after a=x and parameter "Hello, world!".
2313 ClearBreakPoint(bp);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002314 SetBreakPoint(foo, foo_break_position_2);
Steve Blocka7e24c12009-10-30 11:49:00 +00002315 checks = checks_hh;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002316 foo->Call(context, env->Global(), 1, argv_foo).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002317
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002318 // Test that overriding Object.prototype will not interfere into evaluation
2319 // on call frame.
2320 v8::Local<v8::Function> zoo =
2321 CompileFunction(&env,
2322 "x = undefined;"
2323 "function zoo(t) {"
2324 " var a=x;"
2325 " Object.prototype.x = 42;"
2326 " x=t;"
2327 " y=0;" // To ensure break location.
2328 " delete Object.prototype.x;"
2329 " x=a;"
2330 "}",
2331 "zoo");
2332 const int zoo_break_position = 50;
2333
2334 // Arguments with one parameter "Hello, world!"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002335 v8::Local<v8::Value> argv_zoo[1] = {
2336 v8_str(env->GetIsolate(), "Hello, world!")};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002337
2338 // Call zoo with breakpoint set at y=0.
2339 DebugEventCounterClear();
2340 bp = SetBreakPoint(zoo, zoo_break_position);
2341 checks = checks_hu;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002342 zoo->Call(context, env->Global(), 1, argv_zoo).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002343 CHECK_EQ(1, break_point_hit_count);
2344 ClearBreakPoint(bp);
2345
Steve Blocka7e24c12009-10-30 11:49:00 +00002346 // Test function with an inner function. The "y=0" is in function barbar
2347 // to provide a break location. For "y=0" the "y" is at position 8 in the
2348 // barbar function therefore setting breakpoint at position 8 will break at
2349 // "y=0" and setting it higher will break after.
2350 v8::Local<v8::Function> bar = CompileFunction(&env,
2351 "y = 0;"
2352 "x = 'Goodbye, world!';"
2353 "function bar(x, b) {"
2354 " var a;"
2355 " function barbar() {"
2356 " y=0; /* To ensure break location.*/"
2357 " a=x;"
2358 " };"
2359 " debug.Debug.clearAllBreakPoints();"
2360 " barbar();"
2361 " y=0;a=x;"
2362 "}",
2363 "bar");
2364 const int barbar_break_position = 8;
2365
2366 // Call bar setting breakpoint before a=x in barbar and undefined as
2367 // parameter.
2368 checks = checks_uu;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002369 v8::Local<v8::Value> argv_bar_1[2] = {
2370 v8::Undefined(isolate), v8::Number::New(isolate, barbar_break_position)};
2371 bar->Call(context, env->Global(), 2, argv_bar_1).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002372
2373 // Call bar setting breakpoint before a=x in barbar and parameter
2374 // "Hello, world!".
2375 checks = checks_hu;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002376 v8::Local<v8::Value> argv_bar_2[2] = {
2377 v8_str(env->GetIsolate(), "Hello, world!"),
2378 v8::Number::New(env->GetIsolate(), barbar_break_position)};
2379 bar->Call(context, env->Global(), 2, argv_bar_2).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002380
2381 // Call bar setting breakpoint after a=x in barbar and parameter
2382 // "Hello, world!".
2383 checks = checks_hh;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002384 v8::Local<v8::Value> argv_bar_3[2] = {
2385 v8_str(env->GetIsolate(), "Hello, world!"),
2386 v8::Number::New(env->GetIsolate(), barbar_break_position + 1)};
2387 bar->Call(context, env->Global(), 2, argv_bar_3).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002388
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002389 v8::Debug::SetDebugEventListener(isolate, nullptr);
2390 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002391}
2392
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002393
2394int debugEventCount = 0;
2395static void CheckDebugEvent(const v8::Debug::EventDetails& eventDetails) {
2396 if (eventDetails.GetEvent() == v8::Break) ++debugEventCount;
2397}
2398
2399
2400// Test that the conditional breakpoints work event if code generation from
2401// strings is prohibited in the debugee context.
2402TEST(ConditionalBreakpointWithCodeGenerationDisallowed) {
2403 DebugLocalContext env;
2404 v8::HandleScope scope(env->GetIsolate());
2405 env.ExposeDebug();
2406
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002407 v8::Debug::SetDebugEventListener(env->GetIsolate(), CheckDebugEvent);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002408
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002409 v8::Local<v8::Context> context = env.context();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002410 v8::Local<v8::Function> foo = CompileFunction(&env,
2411 "function foo(x) {\n"
2412 " var s = 'String value2';\n"
2413 " return s + x;\n"
2414 "}",
2415 "foo");
2416
2417 // Set conditional breakpoint with condition 'true'.
2418 CompileRun("debug.Debug.setBreakPoint(foo, 2, 0, 'true')");
2419
2420 debugEventCount = 0;
2421 env->AllowCodeGenerationFromStrings(false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002422 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002423 CHECK_EQ(1, debugEventCount);
2424
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002425 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2426 CheckDebuggerUnloaded(env->GetIsolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002427}
2428
2429
2430bool checkedDebugEvals = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002431v8::Local<v8::Function> checkGlobalEvalFunction;
2432v8::Local<v8::Function> checkFrameEvalFunction;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002433static void CheckDebugEval(const v8::Debug::EventDetails& eventDetails) {
2434 if (eventDetails.GetEvent() == v8::Break) {
2435 ++debugEventCount;
2436 v8::HandleScope handleScope(CcTest::isolate());
2437
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002438 v8::Local<v8::Value> args[] = {eventDetails.GetExecutionState()};
2439 CHECK(
2440 checkGlobalEvalFunction->Call(eventDetails.GetEventContext(),
2441 eventDetails.GetEventContext()->Global(),
2442 1, args)
2443 .ToLocalChecked()
2444 ->IsTrue());
2445 CHECK(checkFrameEvalFunction->Call(eventDetails.GetEventContext(),
2446 eventDetails.GetEventContext()->Global(),
2447 1, args)
2448 .ToLocalChecked()
2449 ->IsTrue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002450 }
2451}
2452
2453
2454// Test that the evaluation of expressions when a break point is hit generates
2455// the correct results in case code generation from strings is disallowed in the
2456// debugee context.
2457TEST(DebugEvaluateWithCodeGenerationDisallowed) {
2458 DebugLocalContext env;
2459 v8::HandleScope scope(env->GetIsolate());
2460 env.ExposeDebug();
2461
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002462 v8::Debug::SetDebugEventListener(env->GetIsolate(), CheckDebugEval);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002463
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002464 v8::Local<v8::Context> context = env.context();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002465 v8::Local<v8::Function> foo = CompileFunction(&env,
2466 "var global = 'Global';\n"
2467 "function foo(x) {\n"
2468 " var local = 'Local';\n"
2469 " debugger;\n"
2470 " return local + x;\n"
2471 "}",
2472 "foo");
2473 checkGlobalEvalFunction = CompileFunction(&env,
2474 "function checkGlobalEval(exec_state) {\n"
2475 " return exec_state.evaluateGlobal('global').value() === 'Global';\n"
2476 "}",
2477 "checkGlobalEval");
2478
2479 checkFrameEvalFunction = CompileFunction(&env,
2480 "function checkFrameEval(exec_state) {\n"
2481 " return exec_state.frame(0).evaluate('local').value() === 'Local';\n"
2482 "}",
2483 "checkFrameEval");
2484 debugEventCount = 0;
2485 env->AllowCodeGenerationFromStrings(false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002486 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002487 CHECK_EQ(1, debugEventCount);
2488
2489 checkGlobalEvalFunction.Clear();
2490 checkFrameEvalFunction.Clear();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002491 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2492 CheckDebuggerUnloaded(env->GetIsolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002493}
2494
2495
Leon Clarkee46be812010-01-19 14:06:41 +00002496// Copies a C string to a 16-bit string. Does not check for buffer overflow.
2497// Does not use the V8 engine to convert strings, so it can be used
2498// in any thread. Returns the length of the string.
2499int AsciiToUtf16(const char* input_buffer, uint16_t* output_buffer) {
2500 int i;
2501 for (i = 0; input_buffer[i] != '\0'; ++i) {
2502 // ASCII does not use chars > 127, but be careful anyway.
2503 output_buffer[i] = static_cast<unsigned char>(input_buffer[i]);
2504 }
2505 output_buffer[i] = 0;
2506 return i;
2507}
2508
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002509
Leon Clarkee46be812010-01-19 14:06:41 +00002510// Copies a 16-bit string to a C string by dropping the high byte of
2511// each character. Does not check for buffer overflow.
2512// Can be used in any thread. Requires string length as an input.
2513int Utf16ToAscii(const uint16_t* input_buffer, int length,
2514 char* output_buffer, int output_len = -1) {
2515 if (output_len >= 0) {
2516 if (length > output_len - 1) {
2517 length = output_len - 1;
2518 }
2519 }
2520
2521 for (int i = 0; i < length; ++i) {
2522 output_buffer[i] = static_cast<char>(input_buffer[i]);
2523 }
2524 output_buffer[length] = '\0';
2525 return length;
2526}
2527
2528
2529// We match parts of the message to get evaluate result int value.
2530bool GetEvaluateStringResult(char *message, char* buffer, int buffer_size) {
Leon Clarked91b9f72010-01-27 17:25:45 +00002531 if (strstr(message, "\"command\":\"evaluate\"") == NULL) {
2532 return false;
2533 }
2534 const char* prefix = "\"text\":\"";
2535 char* pos1 = strstr(message, prefix);
2536 if (pos1 == NULL) {
2537 return false;
2538 }
2539 pos1 += strlen(prefix);
2540 char* pos2 = strchr(pos1, '"');
2541 if (pos2 == NULL) {
Leon Clarkee46be812010-01-19 14:06:41 +00002542 return false;
2543 }
2544 Vector<char> buf(buffer, buffer_size);
Leon Clarked91b9f72010-01-27 17:25:45 +00002545 int len = static_cast<int>(pos2 - pos1);
2546 if (len > buffer_size - 1) {
2547 len = buffer_size - 1;
2548 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002549 StrNCpy(buf, pos1, len);
Leon Clarkee46be812010-01-19 14:06:41 +00002550 buffer[buffer_size - 1] = '\0';
2551 return true;
2552}
2553
2554
2555struct EvaluateResult {
2556 static const int kBufferSize = 20;
2557 char buffer[kBufferSize];
2558};
2559
2560struct DebugProcessDebugMessagesData {
2561 static const int kArraySize = 5;
2562 int counter;
2563 EvaluateResult results[kArraySize];
2564
2565 void reset() {
2566 counter = 0;
2567 }
2568 EvaluateResult* current() {
2569 return &results[counter % kArraySize];
2570 }
2571 void next() {
2572 counter++;
2573 }
2574};
2575
2576DebugProcessDebugMessagesData process_debug_messages_data;
2577
2578static void DebugProcessDebugMessagesHandler(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002579 const v8::Debug::Message& message) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002580 v8::Local<v8::String> json = message.GetJSON();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002581 v8::String::Utf8Value utf8(json);
Leon Clarkee46be812010-01-19 14:06:41 +00002582 EvaluateResult* array_item = process_debug_messages_data.current();
2583
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002584 bool res = GetEvaluateStringResult(*utf8,
Leon Clarkee46be812010-01-19 14:06:41 +00002585 array_item->buffer,
2586 EvaluateResult::kBufferSize);
2587 if (res) {
2588 process_debug_messages_data.next();
2589 }
2590}
2591
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002592
Leon Clarkee46be812010-01-19 14:06:41 +00002593// Test that the evaluation of expressions works even from ProcessDebugMessages
2594// i.e. with empty stack.
2595TEST(DebugEvaluateWithoutStack) {
Leon Clarkee46be812010-01-19 14:06:41 +00002596 DebugLocalContext env;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002597 v8::Debug::SetMessageHandler(env->GetIsolate(),
2598 DebugProcessDebugMessagesHandler);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002599 v8::HandleScope scope(env->GetIsolate());
Leon Clarkee46be812010-01-19 14:06:41 +00002600
2601 const char* source =
2602 "var v1 = 'Pinguin';\n function getAnimal() { return 'Capy' + 'bara'; }";
2603
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002604 v8::Local<v8::Context> context = env.context();
2605 v8::Script::Compile(context, v8_str(env->GetIsolate(), source))
2606 .ToLocalChecked()
2607 ->Run(context)
2608 .ToLocalChecked();
Leon Clarkee46be812010-01-19 14:06:41 +00002609
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002610 v8::Debug::ProcessDebugMessages(env->GetIsolate());
Leon Clarkee46be812010-01-19 14:06:41 +00002611
2612 const int kBufferSize = 1000;
2613 uint16_t buffer[kBufferSize];
2614
2615 const char* command_111 = "{\"seq\":111,"
2616 "\"type\":\"request\","
2617 "\"command\":\"evaluate\","
2618 "\"arguments\":{"
2619 " \"global\":true,"
2620 " \"expression\":\"v1\",\"disable_break\":true"
2621 "}}";
2622
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002623 v8::Isolate* isolate = CcTest::isolate();
2624 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_111, buffer));
Leon Clarkee46be812010-01-19 14:06:41 +00002625
2626 const char* command_112 = "{\"seq\":112,"
2627 "\"type\":\"request\","
2628 "\"command\":\"evaluate\","
2629 "\"arguments\":{"
2630 " \"global\":true,"
2631 " \"expression\":\"getAnimal()\",\"disable_break\":true"
2632 "}}";
2633
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002634 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_112, buffer));
Leon Clarkee46be812010-01-19 14:06:41 +00002635
2636 const char* command_113 = "{\"seq\":113,"
2637 "\"type\":\"request\","
2638 "\"command\":\"evaluate\","
2639 "\"arguments\":{"
2640 " \"global\":true,"
2641 " \"expression\":\"239 + 566\",\"disable_break\":true"
2642 "}}";
2643
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002644 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_113, buffer));
Leon Clarkee46be812010-01-19 14:06:41 +00002645
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002646 v8::Debug::ProcessDebugMessages(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00002647
2648 CHECK_EQ(3, process_debug_messages_data.counter);
2649
Leon Clarked91b9f72010-01-27 17:25:45 +00002650 CHECK_EQ(strcmp("Pinguin", process_debug_messages_data.results[0].buffer), 0);
2651 CHECK_EQ(strcmp("Capybara", process_debug_messages_data.results[1].buffer),
2652 0);
2653 CHECK_EQ(strcmp("805", process_debug_messages_data.results[2].buffer), 0);
Leon Clarkee46be812010-01-19 14:06:41 +00002654
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002655 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
2656 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2657 CheckDebuggerUnloaded(env->GetIsolate());
Leon Clarkee46be812010-01-19 14:06:41 +00002658}
2659
Steve Blocka7e24c12009-10-30 11:49:00 +00002660
2661// Simple test of the stepping mechanism using only store ICs.
2662TEST(DebugStepLinear) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002663 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002664 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002665
2666 // Create a function for testing stepping.
2667 v8::Local<v8::Function> foo = CompileFunction(&env,
2668 "function foo(){a=1;b=1;c=1;}",
2669 "foo");
Ben Murdochb0fe1622011-05-05 13:52:32 +01002670
2671 // Run foo to allow it to get optimized.
2672 CompileRun("a=0; b=0; c=0; foo();");
2673
Steve Blocka7e24c12009-10-30 11:49:00 +00002674 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002675 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
2676
2677 SetBreakPoint(foo, 3);
Steve Blocka7e24c12009-10-30 11:49:00 +00002678
2679 step_action = StepIn;
2680 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002681 v8::Local<v8::Context> context = env.context();
2682 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002683
2684 // With stepping all break locations are hit.
2685 CHECK_EQ(4, break_point_hit_count);
2686
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002687 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2688 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002689
2690 // Register a debug event listener which just counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002691 v8::Debug::SetDebugEventListener(env->GetIsolate(),
2692 DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00002693
2694 SetBreakPoint(foo, 3);
2695 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002696 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002697
2698 // Without stepping only active break points are hit.
2699 CHECK_EQ(1, break_point_hit_count);
2700
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002701 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2702 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002703}
2704
2705
2706// Test of the stepping mechanism for keyed load in a loop.
2707TEST(DebugStepKeyedLoadLoop) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002708 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002709 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002710
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002711 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002712 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002713
Steve Blocka7e24c12009-10-30 11:49:00 +00002714 // Create a function for testing stepping of keyed load. The statement 'y=1'
2715 // is there to have more than one breakable statement in the loop, TODO(315).
2716 v8::Local<v8::Function> foo = CompileFunction(
2717 &env,
2718 "function foo(a) {\n"
2719 " var x;\n"
2720 " var len = a.length;\n"
2721 " for (var i = 0; i < len; i++) {\n"
2722 " y = 1;\n"
2723 " x = a[i];\n"
2724 " }\n"
Ben Murdochb0fe1622011-05-05 13:52:32 +01002725 "}\n"
2726 "y=0\n",
Steve Blocka7e24c12009-10-30 11:49:00 +00002727 "foo");
2728
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002729 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00002730 // Create array [0,1,2,3,4,5,6,7,8,9]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002731 v8::Local<v8::Array> a = v8::Array::New(env->GetIsolate(), 10);
Steve Blocka7e24c12009-10-30 11:49:00 +00002732 for (int i = 0; i < 10; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002733 CHECK(a->Set(context, v8::Number::New(env->GetIsolate(), i),
2734 v8::Number::New(env->GetIsolate(), i))
2735 .FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002736 }
2737
2738 // Call function without any break points to ensure inlining is in place.
2739 const int kArgc = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002740 v8::Local<v8::Value> args[kArgc] = {a};
2741 foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002742
2743 // Set up break point and step through the function.
2744 SetBreakPoint(foo, 3);
2745 step_action = StepNext;
2746 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002747 foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002748
2749 // With stepping all break locations are hit.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002750 CHECK_EQ(45, break_point_hit_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002751
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002752 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2753 CheckDebuggerUnloaded(env->GetIsolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002754}
2755
2756
2757// Test of the stepping mechanism for keyed store in a loop.
2758TEST(DebugStepKeyedStoreLoop) {
2759 DebugLocalContext env;
2760 v8::HandleScope scope(env->GetIsolate());
2761
2762 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002763 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002764
2765 // Create a function for testing stepping of keyed store. The statement 'y=1'
2766 // is there to have more than one breakable statement in the loop, TODO(315).
2767 v8::Local<v8::Function> foo = CompileFunction(
2768 &env,
2769 "function foo(a) {\n"
2770 " var len = a.length;\n"
2771 " for (var i = 0; i < len; i++) {\n"
2772 " y = 1;\n"
2773 " a[i] = 42;\n"
2774 " }\n"
2775 "}\n"
2776 "y=0\n",
2777 "foo");
2778
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002779 v8::Local<v8::Context> context = env.context();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002780 // Create array [0,1,2,3,4,5,6,7,8,9]
2781 v8::Local<v8::Array> a = v8::Array::New(env->GetIsolate(), 10);
2782 for (int i = 0; i < 10; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002783 CHECK(a->Set(context, v8::Number::New(env->GetIsolate(), i),
2784 v8::Number::New(env->GetIsolate(), i))
2785 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00002786 }
2787
2788 // Call function without any break points to ensure inlining is in place.
2789 const int kArgc = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002790 v8::Local<v8::Value> args[kArgc] = {a};
2791 foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002792
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002793 // Set up break point and step through the function.
Steve Blocka7e24c12009-10-30 11:49:00 +00002794 SetBreakPoint(foo, 3);
2795 step_action = StepNext;
2796 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002797 foo->Call(context, env->Global(), kArgc, args).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002798
2799 // With stepping all break locations are hit.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002800 CHECK_EQ(44, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002801
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002802 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2803 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002804}
2805
2806
Kristian Monsen25f61362010-05-21 11:50:48 +01002807// Test of the stepping mechanism for named load in a loop.
2808TEST(DebugStepNamedLoadLoop) {
Kristian Monsen25f61362010-05-21 11:50:48 +01002809 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002810 v8::HandleScope scope(env->GetIsolate());
Kristian Monsen25f61362010-05-21 11:50:48 +01002811
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002812 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002813 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002814
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002815 v8::Local<v8::Context> context = env.context();
Kristian Monsen25f61362010-05-21 11:50:48 +01002816 // Create a function for testing stepping of named load.
2817 v8::Local<v8::Function> foo = CompileFunction(
2818 &env,
2819 "function foo() {\n"
2820 " var a = [];\n"
2821 " var s = \"\";\n"
2822 " for (var i = 0; i < 10; i++) {\n"
2823 " var v = new V(i, i + 1);\n"
2824 " v.y;\n"
2825 " a.length;\n" // Special case: array length.
2826 " s.length;\n" // Special case: string length.
2827 " }\n"
2828 "}\n"
2829 "function V(x, y) {\n"
2830 " this.x = x;\n"
2831 " this.y = y;\n"
2832 "}\n",
2833 "foo");
2834
2835 // Call function without any break points to ensure inlining is in place.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002836 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Kristian Monsen25f61362010-05-21 11:50:48 +01002837
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002838 // Set up break point and step through the function.
Kristian Monsen25f61362010-05-21 11:50:48 +01002839 SetBreakPoint(foo, 4);
2840 step_action = StepNext;
2841 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002842 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Kristian Monsen25f61362010-05-21 11:50:48 +01002843
2844 // With stepping all break locations are hit.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002845 CHECK_EQ(65, break_point_hit_count);
Kristian Monsen25f61362010-05-21 11:50:48 +01002846
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002847 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2848 CheckDebuggerUnloaded(env->GetIsolate());
Kristian Monsen25f61362010-05-21 11:50:48 +01002849}
2850
2851
Ben Murdochb0fe1622011-05-05 13:52:32 +01002852static void DoDebugStepNamedStoreLoop(int expected) {
Iain Merrick75681382010-08-19 15:07:18 +01002853 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002854 v8::HandleScope scope(env->GetIsolate());
Iain Merrick75681382010-08-19 15:07:18 +01002855
Ben Murdochb0fe1622011-05-05 13:52:32 +01002856 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002857 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Iain Merrick75681382010-08-19 15:07:18 +01002858
2859 // Create a function for testing stepping of named store.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002860 v8::Local<v8::Context> context = env.context();
Iain Merrick75681382010-08-19 15:07:18 +01002861 v8::Local<v8::Function> foo = CompileFunction(
2862 &env,
2863 "function foo() {\n"
2864 " var a = {a:1};\n"
2865 " for (var i = 0; i < 10; i++) {\n"
2866 " a.a = 2\n"
2867 " }\n"
2868 "}\n",
2869 "foo");
2870
2871 // Call function without any break points to ensure inlining is in place.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002872 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Iain Merrick75681382010-08-19 15:07:18 +01002873
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002874 // Set up break point and step through the function.
Iain Merrick75681382010-08-19 15:07:18 +01002875 SetBreakPoint(foo, 3);
2876 step_action = StepNext;
2877 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002878 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Iain Merrick75681382010-08-19 15:07:18 +01002879
2880 // With stepping all expected break locations are hit.
2881 CHECK_EQ(expected, break_point_hit_count);
2882
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002883 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2884 CheckDebuggerUnloaded(env->GetIsolate());
Iain Merrick75681382010-08-19 15:07:18 +01002885}
2886
2887
2888// Test of the stepping mechanism for named load in a loop.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002889TEST(DebugStepNamedStoreLoop) { DoDebugStepNamedStoreLoop(34); }
Iain Merrick75681382010-08-19 15:07:18 +01002890
2891
Steve Blocka7e24c12009-10-30 11:49:00 +00002892// Test the stepping mechanism with different ICs.
2893TEST(DebugStepLinearMixedICs) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002894 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002895 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002896
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002897 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002898 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002899
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002900 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00002901 // Create a function for testing stepping.
2902 v8::Local<v8::Function> foo = CompileFunction(&env,
2903 "function bar() {};"
2904 "function foo() {"
2905 " var x;"
2906 " var index='name';"
2907 " var y = {};"
2908 " a=1;b=2;x=a;y[index]=3;x=y[index];bar();}", "foo");
Ben Murdochb0fe1622011-05-05 13:52:32 +01002909
2910 // Run functions to allow them to get optimized.
2911 CompileRun("a=0; b=0; bar(); foo();");
2912
Steve Blocka7e24c12009-10-30 11:49:00 +00002913 SetBreakPoint(foo, 0);
2914
Steve Blocka7e24c12009-10-30 11:49:00 +00002915 step_action = StepIn;
2916 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002917 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002918
2919 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002920 CHECK_EQ(11, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002921
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002922 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2923 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002924
2925 // Register a debug event listener which just counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002926 v8::Debug::SetDebugEventListener(env->GetIsolate(),
2927 DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00002928
2929 SetBreakPoint(foo, 0);
2930 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002931 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002932
2933 // Without stepping only active break points are hit.
2934 CHECK_EQ(1, break_point_hit_count);
2935
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002936 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2937 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002938}
2939
2940
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002941TEST(DebugStepDeclarations) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002942 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002943 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002944
2945 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002946 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002947
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002948 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002949 // Create a function for testing stepping. Run it to allow it to get
2950 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002951 const char* src = "function foo() { "
2952 " var a;"
2953 " var b = 1;"
2954 " var c = foo;"
2955 " var d = Math.floor;"
2956 " var e = b + d(1.2);"
Ben Murdochb0fe1622011-05-05 13:52:32 +01002957 "}"
2958 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002959 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
Ben Murdochb0fe1622011-05-05 13:52:32 +01002960
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002961 SetBreakPoint(foo, 0);
2962
2963 // Stepping through the declarations.
2964 step_action = StepIn;
2965 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002966 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002967 CHECK_EQ(6, break_point_hit_count);
2968
2969 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002970 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2971 CheckDebuggerUnloaded(env->GetIsolate());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002972}
2973
2974
2975TEST(DebugStepLocals) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002976 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002977 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002978
2979 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002980 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002981
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002982 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002983 // Create a function for testing stepping. Run it to allow it to get
2984 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002985 const char* src = "function foo() { "
2986 " var a,b;"
2987 " a = 1;"
2988 " b = a + 2;"
2989 " b = 1 + 2 + 3;"
2990 " a = Math.floor(b);"
Ben Murdochb0fe1622011-05-05 13:52:32 +01002991 "}"
2992 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002993 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
Ben Murdochb0fe1622011-05-05 13:52:32 +01002994
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002995 SetBreakPoint(foo, 0);
2996
2997 // Stepping through the declarations.
2998 step_action = StepIn;
2999 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003000 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003001 CHECK_EQ(6, break_point_hit_count);
3002
3003 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003004 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3005 CheckDebuggerUnloaded(env->GetIsolate());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003006}
3007
3008
Steve Blocka7e24c12009-10-30 11:49:00 +00003009TEST(DebugStepIf) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003010 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003011 v8::Isolate* isolate = env->GetIsolate();
3012 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003013
3014 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003015 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Steve Blocka7e24c12009-10-30 11:49:00 +00003016
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003017 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003018 // Create a function for testing stepping. Run it to allow it to get
3019 // optimized.
Steve Blocka7e24c12009-10-30 11:49:00 +00003020 const int argc = 1;
3021 const char* src = "function foo(x) { "
3022 " a = 1;"
3023 " if (x) {"
3024 " b = 1;"
3025 " } else {"
3026 " c = 1;"
3027 " d = 1;"
3028 " }"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003029 "}"
3030 "a=0; b=0; c=0; d=0; foo()";
Steve Blocka7e24c12009-10-30 11:49:00 +00003031 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3032 SetBreakPoint(foo, 0);
3033
3034 // Stepping through the true part.
3035 step_action = StepIn;
3036 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003037 v8::Local<v8::Value> argv_true[argc] = {v8::True(isolate)};
3038 foo->Call(context, env->Global(), argc, argv_true).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003039 CHECK_EQ(4, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003040
3041 // Stepping through the false part.
3042 step_action = StepIn;
3043 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003044 v8::Local<v8::Value> argv_false[argc] = {v8::False(isolate)};
3045 foo->Call(context, env->Global(), argc, argv_false).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003046 CHECK_EQ(5, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003047
3048 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003049 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3050 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003051}
3052
3053
3054TEST(DebugStepSwitch) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003055 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003056 v8::Isolate* isolate = env->GetIsolate();
3057 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003058
3059 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003060 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
Steve Blocka7e24c12009-10-30 11:49:00 +00003061
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003062 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003063 // Create a function for testing stepping. Run it to allow it to get
3064 // optimized.
Steve Blocka7e24c12009-10-30 11:49:00 +00003065 const int argc = 1;
3066 const char* src = "function foo(x) { "
3067 " a = 1;"
3068 " switch (x) {"
3069 " case 1:"
3070 " b = 1;"
3071 " case 2:"
3072 " c = 1;"
3073 " break;"
3074 " case 3:"
3075 " d = 1;"
3076 " e = 1;"
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003077 " f = 1;"
Steve Blocka7e24c12009-10-30 11:49:00 +00003078 " break;"
3079 " }"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003080 "}"
3081 "a=0; b=0; c=0; d=0; e=0; f=0; foo()";
Steve Blocka7e24c12009-10-30 11:49:00 +00003082 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3083 SetBreakPoint(foo, 0);
3084
3085 // One case with fall-through.
3086 step_action = StepIn;
3087 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003088 v8::Local<v8::Value> argv_1[argc] = {v8::Number::New(isolate, 1)};
3089 foo->Call(context, env->Global(), argc, argv_1).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003090 CHECK_EQ(6, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003091
3092 // Another case.
3093 step_action = StepIn;
3094 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003095 v8::Local<v8::Value> argv_2[argc] = {v8::Number::New(isolate, 2)};
3096 foo->Call(context, env->Global(), argc, argv_2).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003097 CHECK_EQ(5, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003098
3099 // Last case.
3100 step_action = StepIn;
3101 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003102 v8::Local<v8::Value> argv_3[argc] = {v8::Number::New(isolate, 3)};
3103 foo->Call(context, env->Global(), argc, argv_3).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003104 CHECK_EQ(7, break_point_hit_count);
3105
3106 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003107 v8::Debug::SetDebugEventListener(isolate, nullptr);
3108 CheckDebuggerUnloaded(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003109}
3110
3111
3112TEST(DebugStepWhile) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003113 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003114 v8::Isolate* isolate = env->GetIsolate();
3115 v8::HandleScope scope(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003116
3117 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003118 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003119
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003120 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003121 // Create a function for testing stepping. Run it to allow it to get
3122 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003123 const int argc = 1;
3124 const char* src = "function foo(x) { "
3125 " var a = 0;"
3126 " while (a < x) {"
3127 " a++;"
3128 " }"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003129 "}"
3130 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003131 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3132 SetBreakPoint(foo, 8); // "var a = 0;"
3133
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003134 // Looping 0 times. We still should break at the while-condition once.
3135 step_action = StepIn;
3136 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003137 v8::Local<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
3138 foo->Call(context, env->Global(), argc, argv_0).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003139 CHECK_EQ(3, break_point_hit_count);
3140
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003141 // Looping 10 times.
3142 step_action = StepIn;
3143 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003144 v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
3145 foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003146 CHECK_EQ(23, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003147
3148 // Looping 100 times.
3149 step_action = StepIn;
3150 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003151 v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
3152 foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003153 CHECK_EQ(203, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003154
3155 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003156 v8::Debug::SetDebugEventListener(isolate, nullptr);
3157 CheckDebuggerUnloaded(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003158}
3159
3160
3161TEST(DebugStepDoWhile) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003162 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003163 v8::Isolate* isolate = env->GetIsolate();
3164 v8::HandleScope scope(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003165
3166 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003167 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003168
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003169 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003170 // Create a function for testing stepping. Run it to allow it to get
3171 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003172 const int argc = 1;
3173 const char* src = "function foo(x) { "
3174 " var a = 0;"
3175 " do {"
3176 " a++;"
3177 " } while (a < x)"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003178 "}"
3179 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003180 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3181 SetBreakPoint(foo, 8); // "var a = 0;"
3182
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003183 // Looping 0 times.
3184 step_action = StepIn;
3185 break_point_hit_count = 0;
3186 v8::Local<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
3187 foo->Call(context, env->Global(), argc, argv_0).ToLocalChecked();
3188 CHECK_EQ(4, break_point_hit_count);
3189
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003190 // Looping 10 times.
3191 step_action = StepIn;
3192 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003193 v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
3194 foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003195 CHECK_EQ(22, break_point_hit_count);
3196
3197 // Looping 100 times.
3198 step_action = StepIn;
3199 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003200 v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
3201 foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003202 CHECK_EQ(202, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003203
3204 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003205 v8::Debug::SetDebugEventListener(isolate, nullptr);
3206 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003207}
3208
3209
3210TEST(DebugStepFor) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003211 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003212 v8::Isolate* isolate = env->GetIsolate();
3213 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003214
3215 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003216 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
Steve Blocka7e24c12009-10-30 11:49:00 +00003217
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003218 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003219 // Create a function for testing stepping. Run it to allow it to get
3220 // optimized.
Steve Blocka7e24c12009-10-30 11:49:00 +00003221 const int argc = 1;
3222 const char* src = "function foo(x) { "
3223 " a = 1;"
3224 " for (i = 0; i < x; i++) {"
3225 " b = 1;"
3226 " }"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003227 "}"
3228 "a=0; b=0; i=0; foo()";
Steve Blocka7e24c12009-10-30 11:49:00 +00003229 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
Ben Murdochb0fe1622011-05-05 13:52:32 +01003230
Steve Blocka7e24c12009-10-30 11:49:00 +00003231 SetBreakPoint(foo, 8); // "a = 1;"
3232
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003233 // Looping 0 times.
3234 step_action = StepIn;
3235 break_point_hit_count = 0;
3236 v8::Local<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
3237 foo->Call(context, env->Global(), argc, argv_0).ToLocalChecked();
3238 CHECK_EQ(4, break_point_hit_count);
3239
Steve Blocka7e24c12009-10-30 11:49:00 +00003240 // Looping 10 times.
3241 step_action = StepIn;
3242 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003243 v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
3244 foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
3245 CHECK_EQ(34, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003246
3247 // Looping 100 times.
3248 step_action = StepIn;
3249 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003250 v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
3251 foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
3252 CHECK_EQ(304, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003253
3254 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003255 v8::Debug::SetDebugEventListener(isolate, nullptr);
3256 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003257}
3258
3259
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003260TEST(DebugStepForContinue) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003261 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003262 v8::Isolate* isolate = env->GetIsolate();
3263 v8::HandleScope scope(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003264
3265 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003266 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003267
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003268 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003269 // Create a function for testing stepping. Run it to allow it to get
3270 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003271 const int argc = 1;
3272 const char* src = "function foo(x) { "
3273 " var a = 0;"
3274 " var b = 0;"
3275 " var c = 0;"
3276 " for (var i = 0; i < x; i++) {"
3277 " a++;"
3278 " if (a % 2 == 0) continue;"
3279 " b++;"
3280 " c++;"
3281 " }"
3282 " return b;"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003283 "}"
3284 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003285 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003286 v8::Local<v8::Value> result;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003287 SetBreakPoint(foo, 8); // "var a = 0;"
3288
3289 // Each loop generates 4 or 5 steps depending on whether a is equal.
3290
3291 // Looping 10 times.
3292 step_action = StepIn;
3293 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003294 v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
3295 result = foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
3296 CHECK_EQ(5, result->Int32Value(context).FromJust());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003297 CHECK_EQ(62, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003298
3299 // Looping 100 times.
3300 step_action = StepIn;
3301 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003302 v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
3303 result = foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
3304 CHECK_EQ(50, result->Int32Value(context).FromJust());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003305 CHECK_EQ(557, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003306
3307 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003308 v8::Debug::SetDebugEventListener(isolate, nullptr);
3309 CheckDebuggerUnloaded(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003310}
3311
3312
3313TEST(DebugStepForBreak) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003314 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003315 v8::Isolate* isolate = env->GetIsolate();
3316 v8::HandleScope scope(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003317
3318 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003319 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003320
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003321 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003322 // Create a function for testing stepping. Run it to allow it to get
3323 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003324 const int argc = 1;
3325 const char* src = "function foo(x) { "
3326 " var a = 0;"
3327 " var b = 0;"
3328 " var c = 0;"
3329 " for (var i = 0; i < 1000; i++) {"
3330 " a++;"
3331 " if (a == x) break;"
3332 " b++;"
3333 " c++;"
3334 " }"
3335 " return b;"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003336 "}"
3337 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003338 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003339 v8::Local<v8::Value> result;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003340 SetBreakPoint(foo, 8); // "var a = 0;"
3341
3342 // Each loop generates 5 steps except for the last (when break is executed)
3343 // which only generates 4.
3344
3345 // Looping 10 times.
3346 step_action = StepIn;
3347 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003348 v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
3349 result = foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
3350 CHECK_EQ(9, result->Int32Value(context).FromJust());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003351 CHECK_EQ(64, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003352
3353 // Looping 100 times.
3354 step_action = StepIn;
3355 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003356 v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
3357 result = foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
3358 CHECK_EQ(99, result->Int32Value(context).FromJust());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003359 CHECK_EQ(604, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003360
3361 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003362 v8::Debug::SetDebugEventListener(isolate, nullptr);
3363 CheckDebuggerUnloaded(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003364}
3365
3366
3367TEST(DebugStepForIn) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003368 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003369 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003370
3371 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003372 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003373
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003374 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003375 // Create a function for testing stepping. Run it to allow it to get
3376 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003377 v8::Local<v8::Function> foo;
3378 const char* src_1 = "function foo() { "
3379 " var a = [1, 2];"
3380 " for (x in a) {"
3381 " b = 0;"
3382 " }"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003383 "}"
3384 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003385 foo = CompileFunction(&env, src_1, "foo");
3386 SetBreakPoint(foo, 0); // "var a = ..."
3387
3388 step_action = StepIn;
3389 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003390 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003391 CHECK_EQ(8, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003392
Ben Murdochb0fe1622011-05-05 13:52:32 +01003393 // Create a function for testing stepping. Run it to allow it to get
3394 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003395 const char* src_2 = "function foo() { "
3396 " var a = {a:[1, 2, 3]};"
3397 " for (x in a.a) {"
3398 " b = 0;"
3399 " }"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003400 "}"
3401 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003402 foo = CompileFunction(&env, src_2, "foo");
3403 SetBreakPoint(foo, 0); // "var a = ..."
3404
3405 step_action = StepIn;
3406 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003407 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003408 CHECK_EQ(10, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003409
3410 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003411 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3412 CheckDebuggerUnloaded(env->GetIsolate());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003413}
3414
3415
3416TEST(DebugStepWith) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003417 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003418 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003419
3420 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003421 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003422
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003423 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003424 // Create a function for testing stepping. Run it to allow it to get
3425 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003426 const char* src = "function foo(x) { "
3427 " var a = {};"
3428 " with (a) {}"
3429 " with (b) {}"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003430 "}"
3431 "foo()";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003432 CHECK(env->Global()
3433 ->Set(context, v8_str(env->GetIsolate(), "b"),
3434 v8::Object::New(env->GetIsolate()))
3435 .FromJust());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003436 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003437 v8::Local<v8::Value> result;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003438 SetBreakPoint(foo, 8); // "var a = {};"
3439
3440 step_action = StepIn;
3441 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003442 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003443 CHECK_EQ(4, break_point_hit_count);
3444
3445 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003446 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3447 CheckDebuggerUnloaded(env->GetIsolate());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003448}
3449
3450
3451TEST(DebugConditional) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003452 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003453 v8::Isolate* isolate = env->GetIsolate();
3454 v8::HandleScope scope(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003455
3456 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003457 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003458
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003459 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003460 // Create a function for testing stepping. Run it to allow it to get
3461 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003462 const char* src = "function foo(x) { "
3463 " var a;"
3464 " a = x ? 1 : 2;"
3465 " return a;"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003466 "}"
3467 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003468 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3469 SetBreakPoint(foo, 0); // "var a;"
3470
3471 step_action = StepIn;
3472 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003473 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3474 CHECK_EQ(4, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003475
3476 step_action = StepIn;
3477 break_point_hit_count = 0;
3478 const int argc = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003479 v8::Local<v8::Value> argv_true[argc] = {v8::True(isolate)};
3480 foo->Call(context, env->Global(), argc, argv_true).ToLocalChecked();
3481 CHECK_EQ(4, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003482
3483 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003484 v8::Debug::SetDebugEventListener(isolate, nullptr);
3485 CheckDebuggerUnloaded(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003486}
3487
3488
Steve Blocka7e24c12009-10-30 11:49:00 +00003489TEST(StepInOutSimple) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003490 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003491 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003492
3493 // Create a function for checking the function when hitting a break point.
3494 frame_function_name = CompileFunction(&env,
3495 frame_function_name_source,
3496 "frame_function_name");
3497
3498 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003499 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStepSequence);
Steve Blocka7e24c12009-10-30 11:49:00 +00003500
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003501 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003502 // Create a function for testing stepping. Run it to allow it to get
3503 // optimized.
Steve Blocka7e24c12009-10-30 11:49:00 +00003504 const char* src = "function a() {b();c();}; "
3505 "function b() {c();}; "
Ben Murdochb0fe1622011-05-05 13:52:32 +01003506 "function c() {}; "
3507 "a(); b(); c()";
Steve Blocka7e24c12009-10-30 11:49:00 +00003508 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3509 SetBreakPoint(a, 0);
3510
3511 // Step through invocation of a with step in.
3512 step_action = StepIn;
3513 break_point_hit_count = 0;
3514 expected_step_sequence = "abcbaca";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003515 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00003516 CHECK_EQ(StrLength(expected_step_sequence),
3517 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003518
3519 // Step through invocation of a with step next.
3520 step_action = StepNext;
3521 break_point_hit_count = 0;
3522 expected_step_sequence = "aaa";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003523 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00003524 CHECK_EQ(StrLength(expected_step_sequence),
3525 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003526
3527 // Step through invocation of a with step out.
3528 step_action = StepOut;
3529 break_point_hit_count = 0;
3530 expected_step_sequence = "a";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003531 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00003532 CHECK_EQ(StrLength(expected_step_sequence),
3533 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003534
3535 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003536 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3537 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003538}
3539
3540
3541TEST(StepInOutTree) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003542 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003543 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003544
3545 // Create a function for checking the function when hitting a break point.
3546 frame_function_name = CompileFunction(&env,
3547 frame_function_name_source,
3548 "frame_function_name");
3549
3550 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003551 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStepSequence);
Steve Blocka7e24c12009-10-30 11:49:00 +00003552
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003553 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003554 // Create a function for testing stepping. Run it to allow it to get
3555 // optimized.
Steve Blocka7e24c12009-10-30 11:49:00 +00003556 const char* src = "function a() {b(c(d()),d());c(d());d()}; "
3557 "function b(x,y) {c();}; "
3558 "function c(x) {}; "
Ben Murdochb0fe1622011-05-05 13:52:32 +01003559 "function d() {}; "
3560 "a(); b(); c(); d()";
Steve Blocka7e24c12009-10-30 11:49:00 +00003561 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3562 SetBreakPoint(a, 0);
3563
3564 // Step through invocation of a with step in.
3565 step_action = StepIn;
3566 break_point_hit_count = 0;
3567 expected_step_sequence = "adacadabcbadacada";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003568 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00003569 CHECK_EQ(StrLength(expected_step_sequence),
3570 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003571
3572 // Step through invocation of a with step next.
3573 step_action = StepNext;
3574 break_point_hit_count = 0;
3575 expected_step_sequence = "aaaa";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003576 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00003577 CHECK_EQ(StrLength(expected_step_sequence),
3578 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003579
3580 // Step through invocation of a with step out.
3581 step_action = StepOut;
3582 break_point_hit_count = 0;
3583 expected_step_sequence = "a";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003584 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00003585 CHECK_EQ(StrLength(expected_step_sequence),
3586 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003587
3588 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003589 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3590 CheckDebuggerUnloaded(env->GetIsolate(), true);
Steve Blocka7e24c12009-10-30 11:49:00 +00003591}
3592
3593
3594TEST(StepInOutBranch) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003595 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003596 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003597
3598 // Create a function for checking the function when hitting a break point.
3599 frame_function_name = CompileFunction(&env,
3600 frame_function_name_source,
3601 "frame_function_name");
3602
3603 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003604 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStepSequence);
Steve Blocka7e24c12009-10-30 11:49:00 +00003605
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003606 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003607 // Create a function for testing stepping. Run it to allow it to get
3608 // optimized.
Steve Blocka7e24c12009-10-30 11:49:00 +00003609 const char* src = "function a() {b(false);c();}; "
3610 "function b(x) {if(x){c();};}; "
Ben Murdochb0fe1622011-05-05 13:52:32 +01003611 "function c() {}; "
3612 "a(); b(); c()";
Steve Blocka7e24c12009-10-30 11:49:00 +00003613 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3614 SetBreakPoint(a, 0);
3615
3616 // Step through invocation of a.
3617 step_action = StepIn;
3618 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003619 expected_step_sequence = "abbaca";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003620 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00003621 CHECK_EQ(StrLength(expected_step_sequence),
3622 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003623
3624 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003625 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3626 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003627}
3628
3629
3630// Test that step in does not step into native functions.
3631TEST(DebugStepNatives) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003632 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003633 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003634
3635 // Create a function for testing stepping.
3636 v8::Local<v8::Function> foo = CompileFunction(
3637 &env,
3638 "function foo(){debugger;Math.sin(1);}",
3639 "foo");
3640
3641 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003642 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Steve Blocka7e24c12009-10-30 11:49:00 +00003643
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003644 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00003645 step_action = StepIn;
3646 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003647 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00003648
3649 // With stepping all break locations are hit.
3650 CHECK_EQ(3, break_point_hit_count);
3651
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003652 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3653 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003654
3655 // Register a debug event listener which just counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003656 v8::Debug::SetDebugEventListener(env->GetIsolate(),
3657 DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00003658
3659 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003660 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00003661
3662 // Without stepping only active break points are hit.
3663 CHECK_EQ(1, break_point_hit_count);
3664
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003665 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3666 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003667}
3668
3669
3670// Test that step in works with function.apply.
3671TEST(DebugStepFunctionApply) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003672 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003673 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003674
3675 // Create a function for testing stepping.
3676 v8::Local<v8::Function> foo = CompileFunction(
3677 &env,
3678 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3679 "function foo(){ debugger; bar.apply(this, [1,2,3]); }",
3680 "foo");
3681
3682 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003683 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Steve Blocka7e24c12009-10-30 11:49:00 +00003684
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003685 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00003686 step_action = StepIn;
3687 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003688 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00003689
3690 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003691 CHECK_EQ(7, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003692
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003693 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3694 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003695
3696 // Register a debug event listener which just counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003697 v8::Debug::SetDebugEventListener(env->GetIsolate(),
3698 DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00003699
3700 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003701 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00003702
3703 // Without stepping only the debugger statement is hit.
3704 CHECK_EQ(1, break_point_hit_count);
3705
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003706 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3707 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003708}
3709
3710
3711// Test that step in works with function.call.
3712TEST(DebugStepFunctionCall) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003713 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003714 v8::Isolate* isolate = env->GetIsolate();
3715 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003716
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003717 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00003718 // Create a function for testing stepping.
3719 v8::Local<v8::Function> foo = CompileFunction(
3720 &env,
3721 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3722 "function foo(a){ debugger;"
3723 " if (a) {"
3724 " bar.call(this, 1, 2, 3);"
3725 " } else {"
3726 " bar.call(this, 0);"
3727 " }"
3728 "}",
3729 "foo");
3730
3731 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003732 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
Steve Blocka7e24c12009-10-30 11:49:00 +00003733 step_action = StepIn;
3734
3735 // Check stepping where the if condition in bar is false.
3736 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003737 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003738 CHECK_EQ(6, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003739
3740 // Check stepping where the if condition in bar is true.
3741 break_point_hit_count = 0;
3742 const int argc = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003743 v8::Local<v8::Value> argv[argc] = {v8::True(isolate)};
3744 foo->Call(context, env->Global(), argc, argv).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003745 CHECK_EQ(8, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003746
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003747 v8::Debug::SetDebugEventListener(isolate, nullptr);
3748 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003749
3750 // Register a debug event listener which just counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003751 v8::Debug::SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00003752
3753 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003754 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00003755
3756 // Without stepping only the debugger statement is hit.
3757 CHECK_EQ(1, break_point_hit_count);
3758
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003759 v8::Debug::SetDebugEventListener(isolate, nullptr);
3760 CheckDebuggerUnloaded(isolate);
3761}
3762
3763
3764// Test that step in works with Function.call.apply.
3765TEST(DebugStepFunctionCallApply) {
3766 DebugLocalContext env;
3767 v8::Isolate* isolate = env->GetIsolate();
3768 v8::HandleScope scope(isolate);
3769
3770 v8::Local<v8::Context> context = env.context();
3771 // Create a function for testing stepping.
3772 v8::Local<v8::Function> foo =
3773 CompileFunction(&env,
3774 "function bar() { }"
3775 "function foo(){ debugger;"
3776 " Function.call.apply(bar);"
3777 " Function.call.apply(Function.call, "
3778 "[Function.call, bar]);"
3779 "}",
3780 "foo");
3781
3782 // Register a debug event listener which steps and counts.
3783 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
3784 step_action = StepIn;
3785
3786 break_point_hit_count = 0;
3787 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3788 CHECK_EQ(6, break_point_hit_count);
3789
3790 v8::Debug::SetDebugEventListener(isolate, nullptr);
3791 CheckDebuggerUnloaded(isolate);
3792
3793 // Register a debug event listener which just counts.
3794 v8::Debug::SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
3795
3796 break_point_hit_count = 0;
3797 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3798
3799 // Without stepping only the debugger statement is hit.
3800 CHECK_EQ(1, break_point_hit_count);
3801
3802 v8::Debug::SetDebugEventListener(isolate, nullptr);
3803 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003804}
3805
3806
Steve Blockd0582a62009-12-15 09:54:21 +00003807// Tests that breakpoint will be hit if it's set in script.
3808TEST(PauseInScript) {
Steve Blockd0582a62009-12-15 09:54:21 +00003809 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003810 v8::HandleScope scope(env->GetIsolate());
Steve Blockd0582a62009-12-15 09:54:21 +00003811 env.ExposeDebug();
3812
3813 // Register a debug event listener which counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003814 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
Steve Blockd0582a62009-12-15 09:54:21 +00003815
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003816 v8::Local<v8::Context> context = env.context();
Steve Blockd0582a62009-12-15 09:54:21 +00003817 // Create a script that returns a function.
3818 const char* src = "(function (evt) {})";
3819 const char* script_name = "StepInHandlerTest";
3820
3821 // Set breakpoint in the script.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003822 SetScriptBreakPointByNameFromJS(env->GetIsolate(), script_name, 0, -1);
Steve Blockd0582a62009-12-15 09:54:21 +00003823 break_point_hit_count = 0;
3824
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003825 v8::ScriptOrigin origin(v8_str(env->GetIsolate(), script_name),
3826 v8::Integer::New(env->GetIsolate(), 0));
3827 v8::Local<v8::Script> script =
3828 v8::Script::Compile(context, v8_str(env->GetIsolate(), src), &origin)
3829 .ToLocalChecked();
3830 v8::Local<v8::Value> r = script->Run(context).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00003831
3832 CHECK(r->IsFunction());
3833 CHECK_EQ(1, break_point_hit_count);
3834
3835 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003836 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3837 CheckDebuggerUnloaded(env->GetIsolate());
3838}
3839
3840
3841static void DebugEventCounterCheck(int caught, int uncaught, int message) {
3842 CHECK_EQ(caught, exception_hit_count);
3843 CHECK_EQ(uncaught, uncaught_exception_hit_count);
3844 CHECK_EQ(message, message_callback_count);
Steve Blockd0582a62009-12-15 09:54:21 +00003845}
3846
3847
Steve Blocka7e24c12009-10-30 11:49:00 +00003848// Test break on exceptions. For each exception break combination the number
3849// of debug event exception callbacks and message callbacks are collected. The
3850// number of debug event exception callbacks are used to check that the
3851// debugger is called correctly and the number of message callbacks is used to
3852// check that uncaught exceptions are still returned even if there is a break
3853// for them.
3854TEST(BreakOnException) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003855 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003856 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003857 env.ExposeDebug();
3858
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003859 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00003860 // Create functions for testing break on exception.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003861 CompileFunction(&env, "function throws(){throw 1;}", "throws");
Steve Blocka7e24c12009-10-30 11:49:00 +00003862 v8::Local<v8::Function> caught =
3863 CompileFunction(&env,
3864 "function caught(){try {throws();} catch(e) {};}",
3865 "caught");
3866 v8::Local<v8::Function> notCaught =
3867 CompileFunction(&env, "function notCaught(){throws();}", "notCaught");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003868 v8::Local<v8::Function> notCaughtFinally = CompileFunction(
3869 &env, "function notCaughtFinally(){try{throws();}finally{}}",
3870 "notCaughtFinally");
3871 // In this edge case, even though this finally does not propagate the
3872 // exception, the debugger considers this uncaught, since we want to break
3873 // at the first throw for the general case where finally implicitly rethrows.
3874 v8::Local<v8::Function> edgeCaseFinally = CompileFunction(
3875 &env, "function caughtFinally(){L:try{throws();}finally{break L;}}",
3876 "caughtFinally");
Steve Blocka7e24c12009-10-30 11:49:00 +00003877
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003878 env->GetIsolate()->AddMessageListener(MessageCallbackCount);
3879 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
Steve Blocka7e24c12009-10-30 11:49:00 +00003880
Ben Murdoch086aeea2011-05-13 15:57:08 +01003881 // Initial state should be no break on exceptions.
Steve Blocka7e24c12009-10-30 11:49:00 +00003882 DebugEventCounterClear();
3883 MessageCallbackCountClear();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003884 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3885 DebugEventCounterCheck(0, 0, 0);
3886 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3887 DebugEventCounterCheck(0, 0, 1);
3888 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3889 DebugEventCounterCheck(0, 0, 2);
3890 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3891 DebugEventCounterCheck(0, 0, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003892
3893 // No break on exception
3894 DebugEventCounterClear();
3895 MessageCallbackCountClear();
3896 ChangeBreakOnException(false, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003897 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3898 DebugEventCounterCheck(0, 0, 0);
3899 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3900 DebugEventCounterCheck(0, 0, 1);
3901 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3902 DebugEventCounterCheck(0, 0, 2);
3903 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3904 DebugEventCounterCheck(0, 0, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003905
3906 // Break on uncaught exception
3907 DebugEventCounterClear();
3908 MessageCallbackCountClear();
3909 ChangeBreakOnException(false, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003910 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3911 DebugEventCounterCheck(0, 0, 0);
3912 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3913 DebugEventCounterCheck(1, 1, 1);
3914 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3915 DebugEventCounterCheck(2, 2, 2);
3916 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3917 DebugEventCounterCheck(3, 3, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003918
3919 // Break on exception and uncaught exception
3920 DebugEventCounterClear();
3921 MessageCallbackCountClear();
3922 ChangeBreakOnException(true, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003923 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3924 DebugEventCounterCheck(1, 0, 0);
3925 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3926 DebugEventCounterCheck(2, 1, 1);
3927 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3928 DebugEventCounterCheck(3, 2, 2);
3929 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3930 DebugEventCounterCheck(4, 3, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003931
3932 // Break on exception
3933 DebugEventCounterClear();
3934 MessageCallbackCountClear();
3935 ChangeBreakOnException(true, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003936 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3937 DebugEventCounterCheck(1, 0, 0);
3938 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3939 DebugEventCounterCheck(2, 1, 1);
3940 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3941 DebugEventCounterCheck(3, 2, 2);
3942 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3943 DebugEventCounterCheck(4, 3, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003944
3945 // No break on exception using JavaScript
3946 DebugEventCounterClear();
3947 MessageCallbackCountClear();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003948 ChangeBreakOnExceptionFromJS(env->GetIsolate(), false, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003949 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3950 DebugEventCounterCheck(0, 0, 0);
3951 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3952 DebugEventCounterCheck(0, 0, 1);
3953 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3954 DebugEventCounterCheck(0, 0, 2);
3955 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3956 DebugEventCounterCheck(0, 0, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003957
3958 // Break on uncaught exception using JavaScript
3959 DebugEventCounterClear();
3960 MessageCallbackCountClear();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003961 ChangeBreakOnExceptionFromJS(env->GetIsolate(), false, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003962 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3963 DebugEventCounterCheck(0, 0, 0);
3964 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3965 DebugEventCounterCheck(1, 1, 1);
3966 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3967 DebugEventCounterCheck(2, 2, 2);
3968 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3969 DebugEventCounterCheck(3, 3, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003970
3971 // Break on exception and uncaught exception using JavaScript
3972 DebugEventCounterClear();
3973 MessageCallbackCountClear();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003974 ChangeBreakOnExceptionFromJS(env->GetIsolate(), true, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003975 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3976 DebugEventCounterCheck(1, 0, 0);
3977 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3978 DebugEventCounterCheck(2, 1, 1);
3979 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3980 DebugEventCounterCheck(3, 2, 2);
3981 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3982 DebugEventCounterCheck(4, 3, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003983
3984 // Break on exception using JavaScript
3985 DebugEventCounterClear();
3986 MessageCallbackCountClear();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003987 ChangeBreakOnExceptionFromJS(env->GetIsolate(), true, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003988 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3989 DebugEventCounterCheck(1, 0, 0);
3990 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3991 DebugEventCounterCheck(2, 1, 1);
3992 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3993 DebugEventCounterCheck(3, 2, 2);
3994 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3995 DebugEventCounterCheck(4, 3, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003996
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003997 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3998 CheckDebuggerUnloaded(env->GetIsolate());
3999 env->GetIsolate()->RemoveMessageListeners(MessageCallbackCount);
4000}
4001
4002
4003static void try_finally_original_message(v8::Local<v8::Message> message,
4004 v8::Local<v8::Value> data) {
4005 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
4006 CHECK_EQ(2, message->GetLineNumber(context).FromJust());
4007 CHECK_EQ(2, message->GetStartColumn(context).FromJust());
4008 message_callback_count++;
4009}
4010
4011
4012TEST(TryFinallyOriginalMessage) {
4013 // Test that the debugger plays nicely with the pending message.
4014 message_callback_count = 0;
4015 DebugEventCounterClear();
4016 DebugLocalContext env;
4017 v8::Isolate* isolate = CcTest::isolate();
4018 isolate->AddMessageListener(try_finally_original_message);
4019 v8::Debug::SetDebugEventListener(isolate, DebugEventCounter);
4020 ChangeBreakOnException(true, true);
4021 v8::HandleScope scope(isolate);
4022 CompileRun(
4023 "try {\n"
4024 " throw 1;\n"
4025 "} finally {\n"
4026 "}\n");
4027 DebugEventCounterCheck(1, 1, 1);
4028 v8::Debug::SetDebugEventListener(isolate, nullptr);
4029 isolate->RemoveMessageListeners(try_finally_original_message);
Steve Blocka7e24c12009-10-30 11:49:00 +00004030}
4031
4032
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004033TEST(EvalJSInDebugEventListenerOnNativeReThrownException) {
4034 DebugLocalContext env;
4035 v8::HandleScope scope(env->GetIsolate());
4036 env.ExposeDebug();
4037
4038 // Create functions for testing break on exception.
4039 v8::Local<v8::Function> noThrowJS = CompileFunction(
4040 &env, "function noThrowJS(){var a=[1]; a.push(2); return a.length;}",
4041 "noThrowJS");
4042
4043 debug_event_listener_callback = noThrowJS;
4044 debug_event_listener_callback_result = 2;
4045
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004046 env->GetIsolate()->AddMessageListener(MessageCallbackCount);
4047 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004048 // Break on uncaught exception
4049 ChangeBreakOnException(false, true);
4050 DebugEventCounterClear();
4051 MessageCallbackCountClear();
4052
4053 // ReThrow native error
4054 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004055 v8::TryCatch tryCatch(env->GetIsolate());
4056 env->GetIsolate()->ThrowException(
4057 v8::Exception::TypeError(v8_str(env->GetIsolate(), "Type error")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004058 CHECK(tryCatch.HasCaught());
4059 tryCatch.ReThrow();
4060 }
4061 CHECK_EQ(1, exception_hit_count);
4062 CHECK_EQ(1, uncaught_exception_hit_count);
4063 CHECK_EQ(0, message_callback_count); // FIXME: Should it be 1 ?
4064 CHECK(!debug_event_listener_callback.IsEmpty());
4065
4066 debug_event_listener_callback.Clear();
4067}
4068
4069
Steve Blocka7e24c12009-10-30 11:49:00 +00004070// Test break on exception from compiler errors. When compiling using
4071// v8::Script::Compile there is no JavaScript stack whereas when compiling using
4072// eval there are JavaScript frames.
4073TEST(BreakOnCompileException) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004074 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004075 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004076
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004077 v8::Local<v8::Context> context = env.context();
Ben Murdoch086aeea2011-05-13 15:57:08 +01004078 // For this test, we want to break on uncaught exceptions:
4079 ChangeBreakOnException(false, true);
4080
Steve Blocka7e24c12009-10-30 11:49:00 +00004081 // Create a function for checking the function when hitting a break point.
4082 frame_count = CompileFunction(&env, frame_count_source, "frame_count");
4083
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004084 env->GetIsolate()->AddMessageListener(MessageCallbackCount);
4085 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
Steve Blocka7e24c12009-10-30 11:49:00 +00004086
4087 DebugEventCounterClear();
4088 MessageCallbackCountClear();
4089
4090 // Check initial state.
4091 CHECK_EQ(0, exception_hit_count);
4092 CHECK_EQ(0, uncaught_exception_hit_count);
4093 CHECK_EQ(0, message_callback_count);
4094 CHECK_EQ(-1, last_js_stack_height);
4095
4096 // Throws SyntaxError: Unexpected end of input
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004097 CHECK(
4098 v8::Script::Compile(context, v8_str(env->GetIsolate(), "+++")).IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00004099 CHECK_EQ(1, exception_hit_count);
4100 CHECK_EQ(1, uncaught_exception_hit_count);
4101 CHECK_EQ(1, message_callback_count);
4102 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
4103
4104 // Throws SyntaxError: Unexpected identifier
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004105 CHECK(
4106 v8::Script::Compile(context, v8_str(env->GetIsolate(), "x x")).IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00004107 CHECK_EQ(2, exception_hit_count);
4108 CHECK_EQ(2, uncaught_exception_hit_count);
4109 CHECK_EQ(2, message_callback_count);
4110 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
4111
4112 // Throws SyntaxError: Unexpected end of input
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004113 CHECK(v8::Script::Compile(context, v8_str(env->GetIsolate(), "eval('+++')"))
4114 .ToLocalChecked()
4115 ->Run(context)
4116 .IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00004117 CHECK_EQ(3, exception_hit_count);
4118 CHECK_EQ(3, uncaught_exception_hit_count);
4119 CHECK_EQ(3, message_callback_count);
4120 CHECK_EQ(1, last_js_stack_height);
4121
4122 // Throws SyntaxError: Unexpected identifier
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004123 CHECK(v8::Script::Compile(context, v8_str(env->GetIsolate(), "eval('x x')"))
4124 .ToLocalChecked()
4125 ->Run(context)
4126 .IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00004127 CHECK_EQ(4, exception_hit_count);
4128 CHECK_EQ(4, uncaught_exception_hit_count);
4129 CHECK_EQ(4, message_callback_count);
4130 CHECK_EQ(1, last_js_stack_height);
4131}
4132
4133
4134TEST(StepWithException) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004135 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004136 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004137
Ben Murdoch086aeea2011-05-13 15:57:08 +01004138 // For this test, we want to break on uncaught exceptions:
4139 ChangeBreakOnException(false, true);
4140
Steve Blocka7e24c12009-10-30 11:49:00 +00004141 // Create a function for checking the function when hitting a break point.
4142 frame_function_name = CompileFunction(&env,
4143 frame_function_name_source,
4144 "frame_function_name");
4145
4146 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004147 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStepSequence);
Steve Blocka7e24c12009-10-30 11:49:00 +00004148
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004149 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00004150 // Create functions for testing stepping.
4151 const char* src = "function a() { n(); }; "
4152 "function b() { c(); }; "
4153 "function c() { n(); }; "
4154 "function d() { x = 1; try { e(); } catch(x) { x = 2; } }; "
4155 "function e() { n(); }; "
4156 "function f() { x = 1; try { g(); } catch(x) { x = 2; } }; "
4157 "function g() { h(); }; "
4158 "function h() { x = 1; throw 1; }; ";
4159
4160 // Step through invocation of a.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004161 ClearStepping();
Steve Blocka7e24c12009-10-30 11:49:00 +00004162 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
4163 SetBreakPoint(a, 0);
4164 step_action = StepIn;
4165 break_point_hit_count = 0;
4166 expected_step_sequence = "aa";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004167 CHECK(a->Call(context, env->Global(), 0, NULL).IsEmpty());
Steve Blockd0582a62009-12-15 09:54:21 +00004168 CHECK_EQ(StrLength(expected_step_sequence),
4169 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004170
4171 // Step through invocation of b + c.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004172 ClearStepping();
Steve Blocka7e24c12009-10-30 11:49:00 +00004173 v8::Local<v8::Function> b = CompileFunction(&env, src, "b");
4174 SetBreakPoint(b, 0);
4175 step_action = StepIn;
4176 break_point_hit_count = 0;
4177 expected_step_sequence = "bcc";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004178 CHECK(b->Call(context, env->Global(), 0, NULL).IsEmpty());
Steve Blockd0582a62009-12-15 09:54:21 +00004179 CHECK_EQ(StrLength(expected_step_sequence),
4180 break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004181
Steve Blocka7e24c12009-10-30 11:49:00 +00004182 // Step through invocation of d + e.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004183 ClearStepping();
Steve Blocka7e24c12009-10-30 11:49:00 +00004184 v8::Local<v8::Function> d = CompileFunction(&env, src, "d");
4185 SetBreakPoint(d, 0);
4186 ChangeBreakOnException(false, true);
4187 step_action = StepIn;
4188 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004189 expected_step_sequence = "ddedd";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004190 d->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00004191 CHECK_EQ(StrLength(expected_step_sequence),
4192 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004193
4194 // Step through invocation of d + e now with break on caught exceptions.
4195 ChangeBreakOnException(true, true);
4196 step_action = StepIn;
4197 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004198 expected_step_sequence = "ddeedd";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004199 d->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00004200 CHECK_EQ(StrLength(expected_step_sequence),
4201 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004202
4203 // Step through invocation of f + g + h.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004204 ClearStepping();
Steve Blocka7e24c12009-10-30 11:49:00 +00004205 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
4206 SetBreakPoint(f, 0);
4207 ChangeBreakOnException(false, true);
4208 step_action = StepIn;
4209 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004210 expected_step_sequence = "ffghhff";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004211 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00004212 CHECK_EQ(StrLength(expected_step_sequence),
4213 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004214
4215 // Step through invocation of f + g + h now with break on caught exceptions.
4216 ChangeBreakOnException(true, true);
4217 step_action = StepIn;
4218 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004219 expected_step_sequence = "ffghhhff";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004220 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00004221 CHECK_EQ(StrLength(expected_step_sequence),
4222 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004223
4224 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004225 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
4226 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004227}
4228
4229
4230TEST(DebugBreak) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004231 i::FLAG_stress_compaction = false;
4232#ifdef VERIFY_HEAP
4233 i::FLAG_verify_heap = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00004234#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004235 DebugLocalContext env;
4236 v8::Isolate* isolate = env->GetIsolate();
4237 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004238
4239 // Register a debug event listener which sets the break flag and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004240 v8::Debug::SetDebugEventListener(isolate, DebugEventBreak);
Steve Blocka7e24c12009-10-30 11:49:00 +00004241
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004242 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00004243 // Create a function for testing stepping.
4244 const char* src = "function f0() {}"
4245 "function f1(x1) {}"
4246 "function f2(x1,x2) {}"
4247 "function f3(x1,x2,x3) {}";
4248 v8::Local<v8::Function> f0 = CompileFunction(&env, src, "f0");
4249 v8::Local<v8::Function> f1 = CompileFunction(&env, src, "f1");
4250 v8::Local<v8::Function> f2 = CompileFunction(&env, src, "f2");
4251 v8::Local<v8::Function> f3 = CompileFunction(&env, src, "f3");
4252
4253 // Call the function to make sure it is compiled.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004254 v8::Local<v8::Value> argv[] = {
4255 v8::Number::New(isolate, 1), v8::Number::New(isolate, 1),
4256 v8::Number::New(isolate, 1), v8::Number::New(isolate, 1)};
Steve Blocka7e24c12009-10-30 11:49:00 +00004257
4258 // Call all functions to make sure that they are compiled.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004259 f0->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4260 f1->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4261 f2->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4262 f3->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00004263
4264 // Set the debug break flag.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004265 v8::Debug::DebugBreak(env->GetIsolate());
4266 CHECK(v8::Debug::CheckDebugBreak(env->GetIsolate()));
Steve Blocka7e24c12009-10-30 11:49:00 +00004267
4268 // Call all functions with different argument count.
4269 break_point_hit_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004270 for (unsigned int i = 0; i < arraysize(argv); i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004271 f0->Call(context, env->Global(), i, argv).ToLocalChecked();
4272 f1->Call(context, env->Global(), i, argv).ToLocalChecked();
4273 f2->Call(context, env->Global(), i, argv).ToLocalChecked();
4274 f3->Call(context, env->Global(), i, argv).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00004275 }
4276
4277 // One break for each function called.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004278 CHECK(4 * arraysize(argv) == break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004279
4280 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004281 v8::Debug::SetDebugEventListener(isolate, nullptr);
4282 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004283}
4284
4285
4286// Test to ensure that JavaScript code keeps running while the debug break
4287// through the stack limit flag is set but breaks are disabled.
4288TEST(DisableBreak) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004289 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004290 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004291
4292 // Register a debug event listener which sets the break flag and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004293 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
Steve Blocka7e24c12009-10-30 11:49:00 +00004294
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004295 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00004296 // Create a function for testing stepping.
4297 const char* src = "function f() {g()};function g(){i=0; while(i<10){i++}}";
4298 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
4299
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004300 // Set, test and cancel debug break.
4301 v8::Debug::DebugBreak(env->GetIsolate());
4302 CHECK(v8::Debug::CheckDebugBreak(env->GetIsolate()));
4303 v8::Debug::CancelDebugBreak(env->GetIsolate());
4304 CHECK(!v8::Debug::CheckDebugBreak(env->GetIsolate()));
4305
Steve Blocka7e24c12009-10-30 11:49:00 +00004306 // Set the debug break flag.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004307 v8::Debug::DebugBreak(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004308
4309 // Call all functions with different argument count.
4310 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004311 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00004312 CHECK_EQ(1, break_point_hit_count);
4313
4314 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004315 v8::Debug::DebugBreak(env->GetIsolate());
4316 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
4317 v8::internal::DisableBreak disable_break(isolate->debug(), true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004318 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00004319 CHECK_EQ(1, break_point_hit_count);
4320 }
4321
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004322 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00004323 CHECK_EQ(2, break_point_hit_count);
4324
4325 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004326 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
4327 CheckDebuggerUnloaded(env->GetIsolate());
4328}
4329
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004330TEST(DisableDebuggerStatement) {
4331 DebugLocalContext env;
4332 v8::HandleScope scope(env->GetIsolate());
4333
4334 // Register a debug event listener which sets the break flag and counts.
4335 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
4336 CompileRun("debugger;");
4337 CHECK_EQ(1, break_point_hit_count);
4338
4339 // Check that we ignore debugger statement when breakpoints aren't active.
4340 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
4341 isolate->debug()->set_break_points_active(false);
4342 CompileRun("debugger;");
4343 CHECK_EQ(1, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004344}
4345
Leon Clarkee46be812010-01-19 14:06:41 +00004346static const char* kSimpleExtensionSource =
4347 "(function Foo() {"
4348 " return 4;"
4349 "})() ";
4350
4351// http://crbug.com/28933
4352// Test that debug break is disabled when bootstrapper is active.
4353TEST(NoBreakWhenBootstrapping) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004354 v8::Isolate* isolate = CcTest::isolate();
4355 v8::HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00004356
4357 // Register a debug event listener which sets the break flag and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004358 v8::Debug::SetDebugEventListener(isolate, DebugEventCounter);
Leon Clarkee46be812010-01-19 14:06:41 +00004359
4360 // Set the debug break flag.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004361 v8::Debug::DebugBreak(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00004362 break_point_hit_count = 0;
4363 {
4364 // Create a context with an extension to make sure that some JavaScript
4365 // code is executed during bootstrapping.
4366 v8::RegisterExtension(new v8::Extension("simpletest",
4367 kSimpleExtensionSource));
4368 const char* extension_names[] = { "simpletest" };
4369 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004370 v8::HandleScope handle_scope(isolate);
4371 v8::Context::New(isolate, &extensions);
Leon Clarkee46be812010-01-19 14:06:41 +00004372 }
4373 // Check that no DebugBreak events occured during the context creation.
4374 CHECK_EQ(0, break_point_hit_count);
4375
4376 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004377 v8::Debug::SetDebugEventListener(isolate, nullptr);
4378 CheckDebuggerUnloaded(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00004379}
Steve Blocka7e24c12009-10-30 11:49:00 +00004380
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004381
4382static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004383 v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
4384 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
4385 CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 0),
4386 v8_str(info.GetIsolate(), "a"))
4387 .FromJust());
4388 CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 1),
4389 v8_str(info.GetIsolate(), "b"))
4390 .FromJust());
4391 CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 2),
4392 v8_str(info.GetIsolate(), "c"))
4393 .FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004394 info.GetReturnValue().Set(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00004395}
4396
4397
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004398static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
4399 v8::Isolate* isolate = info.GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004400 v8::Local<v8::Array> result = v8::Array::New(isolate, 2);
4401 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
4402 CHECK(result->Set(context, v8::Integer::New(isolate, 0),
4403 v8::Number::New(isolate, 1))
4404 .FromJust());
4405 CHECK(result->Set(context, v8::Integer::New(isolate, 1),
4406 v8::Number::New(isolate, 10))
4407 .FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004408 info.GetReturnValue().Set(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00004409}
4410
4411
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004412static void NamedGetter(v8::Local<v8::Name> name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004413 const v8::PropertyCallbackInfo<v8::Value>& info) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004414 if (name->IsSymbol()) return;
4415 v8::String::Utf8Value n(v8::Local<v8::String>::Cast(name));
Steve Blocka7e24c12009-10-30 11:49:00 +00004416 if (strcmp(*n, "a") == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004417 info.GetReturnValue().Set(v8_str(info.GetIsolate(), "AA"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004418 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00004419 } else if (strcmp(*n, "b") == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004420 info.GetReturnValue().Set(v8_str(info.GetIsolate(), "BB"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004421 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00004422 } else if (strcmp(*n, "c") == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004423 info.GetReturnValue().Set(v8_str(info.GetIsolate(), "CC"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004424 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00004425 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004426 info.GetReturnValue().SetUndefined();
4427 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00004428 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004429 info.GetReturnValue().Set(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00004430}
4431
4432
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004433static void IndexedGetter(uint32_t index,
4434 const v8::PropertyCallbackInfo<v8::Value>& info) {
4435 info.GetReturnValue().Set(static_cast<double>(index + 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00004436}
4437
4438
4439TEST(InterceptorPropertyMirror) {
4440 // Create a V8 environment with debug access.
Steve Blocka7e24c12009-10-30 11:49:00 +00004441 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004442 v8::Isolate* isolate = env->GetIsolate();
4443 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004444 env.ExposeDebug();
4445
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004446 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00004447 // Create object with named interceptor.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004448 v8::Local<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004449 named->SetHandler(v8::NamedPropertyHandlerConfiguration(
4450 NamedGetter, NULL, NULL, NULL, NamedEnum));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004451 CHECK(env->Global()
4452 ->Set(context, v8_str(isolate, "intercepted_named"),
4453 named->NewInstance(context).ToLocalChecked())
4454 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004455
4456 // Create object with indexed interceptor.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004457 v8::Local<v8::ObjectTemplate> indexed = v8::ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004458 indexed->SetHandler(v8::IndexedPropertyHandlerConfiguration(
4459 IndexedGetter, NULL, NULL, NULL, IndexedEnum));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004460 CHECK(env->Global()
4461 ->Set(context, v8_str(isolate, "intercepted_indexed"),
4462 indexed->NewInstance(context).ToLocalChecked())
4463 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004464
4465 // Create object with both named and indexed interceptor.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004466 v8::Local<v8::ObjectTemplate> both = v8::ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004467 both->SetHandler(v8::NamedPropertyHandlerConfiguration(
4468 NamedGetter, NULL, NULL, NULL, NamedEnum));
4469 both->SetHandler(v8::IndexedPropertyHandlerConfiguration(
4470 IndexedGetter, NULL, NULL, NULL, IndexedEnum));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004471 CHECK(env->Global()
4472 ->Set(context, v8_str(isolate, "intercepted_both"),
4473 both->NewInstance(context).ToLocalChecked())
4474 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004475
4476 // Get mirrors for the three objects with interceptor.
4477 CompileRun(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004478 "var named_mirror = debug.MakeMirror(intercepted_named);"
4479 "var indexed_mirror = debug.MakeMirror(intercepted_indexed);"
4480 "var both_mirror = debug.MakeMirror(intercepted_both)");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004481 CHECK(CompileRun("named_mirror instanceof debug.ObjectMirror")
4482 ->BooleanValue(context)
4483 .FromJust());
4484 CHECK(CompileRun("indexed_mirror instanceof debug.ObjectMirror")
4485 ->BooleanValue(context)
4486 .FromJust());
4487 CHECK(CompileRun("both_mirror instanceof debug.ObjectMirror")
4488 ->BooleanValue(context)
4489 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004490
4491 // Get the property names from the interceptors
4492 CompileRun(
4493 "named_names = named_mirror.propertyNames();"
4494 "indexed_names = indexed_mirror.propertyNames();"
4495 "both_names = both_mirror.propertyNames()");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004496 CHECK_EQ(3, CompileRun("named_names.length")->Int32Value(context).FromJust());
4497 CHECK_EQ(2,
4498 CompileRun("indexed_names.length")->Int32Value(context).FromJust());
4499 CHECK_EQ(5, CompileRun("both_names.length")->Int32Value(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004500
4501 // Check the expected number of properties.
4502 const char* source;
4503 source = "named_mirror.properties().length";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004504 CHECK_EQ(3, CompileRun(source)->Int32Value(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004505
4506 source = "indexed_mirror.properties().length";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004507 CHECK_EQ(2, CompileRun(source)->Int32Value(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004508
4509 source = "both_mirror.properties().length";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004510 CHECK_EQ(5, CompileRun(source)->Int32Value(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004511
4512 // Get the interceptor properties for the object with only named interceptor.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004513 CompileRun("var named_values = named_mirror.properties()");
Steve Blocka7e24c12009-10-30 11:49:00 +00004514
4515 // Check that the properties are interceptor properties.
4516 for (int i = 0; i < 3; i++) {
4517 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004518 SNPrintF(buffer,
4519 "named_values[%d] instanceof debug.PropertyMirror", i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004520 CHECK(CompileRun(buffer.start())->BooleanValue(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004521
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004522 SNPrintF(buffer, "named_values[%d].isNative()", i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004523 CHECK(CompileRun(buffer.start())->BooleanValue(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004524 }
4525
4526 // Get the interceptor properties for the object with only indexed
4527 // interceptor.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004528 CompileRun("var indexed_values = indexed_mirror.properties()");
Steve Blocka7e24c12009-10-30 11:49:00 +00004529
4530 // Check that the properties are interceptor properties.
4531 for (int i = 0; i < 2; i++) {
4532 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004533 SNPrintF(buffer,
4534 "indexed_values[%d] instanceof debug.PropertyMirror", i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004535 CHECK(CompileRun(buffer.start())->BooleanValue(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004536 }
4537
4538 // Get the interceptor properties for the object with both types of
4539 // interceptors.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004540 CompileRun("var both_values = both_mirror.properties()");
Steve Blocka7e24c12009-10-30 11:49:00 +00004541
4542 // Check that the properties are interceptor properties.
4543 for (int i = 0; i < 5; i++) {
4544 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004545 SNPrintF(buffer, "both_values[%d] instanceof debug.PropertyMirror", i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004546 CHECK(CompileRun(buffer.start())->BooleanValue(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004547 }
4548
4549 // Check the property names.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004550 source = "both_values[0].name() == '1'";
4551 CHECK(CompileRun(source)->BooleanValue(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004552
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004553 source = "both_values[1].name() == '10'";
4554 CHECK(CompileRun(source)->BooleanValue(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004555
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004556 source = "both_values[2].name() == 'a'";
4557 CHECK(CompileRun(source)->BooleanValue(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004558
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004559 source = "both_values[3].name() == 'b'";
4560 CHECK(CompileRun(source)->BooleanValue(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004561
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004562 source = "both_values[4].name() == 'c'";
4563 CHECK(CompileRun(source)->BooleanValue(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004564}
4565
4566
4567TEST(HiddenPrototypePropertyMirror) {
4568 // Create a V8 environment with debug access.
Steve Blocka7e24c12009-10-30 11:49:00 +00004569 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004570 v8::Isolate* isolate = env->GetIsolate();
4571 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004572 env.ExposeDebug();
4573
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004574 v8::Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
4575 t0->InstanceTemplate()->Set(v8_str(isolate, "x"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004576 v8::Number::New(isolate, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004577 v8::Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004578 t1->SetHiddenPrototype(true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004579 t1->InstanceTemplate()->Set(v8_str(isolate, "y"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004580 v8::Number::New(isolate, 1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004581 v8::Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004582 t2->SetHiddenPrototype(true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004583 t2->InstanceTemplate()->Set(v8_str(isolate, "z"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004584 v8::Number::New(isolate, 2));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004585 v8::Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
4586 t3->InstanceTemplate()->Set(v8_str(isolate, "u"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004587 v8::Number::New(isolate, 3));
Steve Blocka7e24c12009-10-30 11:49:00 +00004588
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004589 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00004590 // Create object and set them on the global object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004591 v8::Local<v8::Object> o0 = t0->GetFunction(context)
4592 .ToLocalChecked()
4593 ->NewInstance(context)
4594 .ToLocalChecked();
4595 CHECK(env->Global()->Set(context, v8_str(isolate, "o0"), o0).FromJust());
4596 v8::Local<v8::Object> o1 = t1->GetFunction(context)
4597 .ToLocalChecked()
4598 ->NewInstance(context)
4599 .ToLocalChecked();
4600 CHECK(env->Global()->Set(context, v8_str(isolate, "o1"), o1).FromJust());
4601 v8::Local<v8::Object> o2 = t2->GetFunction(context)
4602 .ToLocalChecked()
4603 ->NewInstance(context)
4604 .ToLocalChecked();
4605 CHECK(env->Global()->Set(context, v8_str(isolate, "o2"), o2).FromJust());
4606 v8::Local<v8::Object> o3 = t3->GetFunction(context)
4607 .ToLocalChecked()
4608 ->NewInstance(context)
4609 .ToLocalChecked();
4610 CHECK(env->Global()->Set(context, v8_str(isolate, "o3"), o3).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004611
4612 // Get mirrors for the four objects.
4613 CompileRun(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004614 "var o0_mirror = debug.MakeMirror(o0);"
4615 "var o1_mirror = debug.MakeMirror(o1);"
4616 "var o2_mirror = debug.MakeMirror(o2);"
4617 "var o3_mirror = debug.MakeMirror(o3)");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004618 CHECK(CompileRun("o0_mirror instanceof debug.ObjectMirror")
4619 ->BooleanValue(context)
4620 .FromJust());
4621 CHECK(CompileRun("o1_mirror instanceof debug.ObjectMirror")
4622 ->BooleanValue(context)
4623 .FromJust());
4624 CHECK(CompileRun("o2_mirror instanceof debug.ObjectMirror")
4625 ->BooleanValue(context)
4626 .FromJust());
4627 CHECK(CompileRun("o3_mirror instanceof debug.ObjectMirror")
4628 ->BooleanValue(context)
4629 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004630
4631 // Check that each object has one property.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004632 CHECK_EQ(1, CompileRun("o0_mirror.propertyNames().length")
4633 ->Int32Value(context)
4634 .FromJust());
4635 CHECK_EQ(1, CompileRun("o1_mirror.propertyNames().length")
4636 ->Int32Value(context)
4637 .FromJust());
4638 CHECK_EQ(1, CompileRun("o2_mirror.propertyNames().length")
4639 ->Int32Value(context)
4640 .FromJust());
4641 CHECK_EQ(1, CompileRun("o3_mirror.propertyNames().length")
4642 ->Int32Value(context)
4643 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004644
4645 // Set o1 as prototype for o0. o1 has the hidden prototype flag so all
4646 // properties on o1 should be seen on o0.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004647 CHECK(o0->Set(context, v8_str(isolate, "__proto__"), o1).FromJust());
4648 CHECK_EQ(2, CompileRun("o0_mirror.propertyNames().length")
4649 ->Int32Value(context)
4650 .FromJust());
4651 CHECK_EQ(0, CompileRun("o0_mirror.property('x').value().value()")
4652 ->Int32Value(context)
4653 .FromJust());
4654 CHECK_EQ(1, CompileRun("o0_mirror.property('y').value().value()")
4655 ->Int32Value(context)
4656 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004657
4658 // Set o2 as prototype for o0 (it will end up after o1 as o1 has the hidden
4659 // prototype flag. o2 also has the hidden prototype flag so all properties
4660 // on o2 should be seen on o0 as well as properties on o1.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004661 CHECK(o0->Set(context, v8_str(isolate, "__proto__"), o2).FromJust());
4662 CHECK_EQ(3, CompileRun("o0_mirror.propertyNames().length")
4663 ->Int32Value(context)
4664 .FromJust());
4665 CHECK_EQ(0, CompileRun("o0_mirror.property('x').value().value()")
4666 ->Int32Value(context)
4667 .FromJust());
4668 CHECK_EQ(1, CompileRun("o0_mirror.property('y').value().value()")
4669 ->Int32Value(context)
4670 .FromJust());
4671 CHECK_EQ(2, CompileRun("o0_mirror.property('z').value().value()")
4672 ->Int32Value(context)
4673 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004674
4675 // Set o3 as prototype for o0 (it will end up after o1 and o2 as both o1 and
4676 // o2 has the hidden prototype flag. o3 does not have the hidden prototype
4677 // flag so properties on o3 should not be seen on o0 whereas the properties
4678 // from o1 and o2 should still be seen on o0.
4679 // Final prototype chain: o0 -> o1 -> o2 -> o3
4680 // Hidden prototypes: ^^ ^^
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004681 CHECK(o0->Set(context, v8_str(isolate, "__proto__"), o3).FromJust());
4682 CHECK_EQ(3, CompileRun("o0_mirror.propertyNames().length")
4683 ->Int32Value(context)
4684 .FromJust());
4685 CHECK_EQ(1, CompileRun("o3_mirror.propertyNames().length")
4686 ->Int32Value(context)
4687 .FromJust());
4688 CHECK_EQ(0, CompileRun("o0_mirror.property('x').value().value()")
4689 ->Int32Value(context)
4690 .FromJust());
4691 CHECK_EQ(1, CompileRun("o0_mirror.property('y').value().value()")
4692 ->Int32Value(context)
4693 .FromJust());
4694 CHECK_EQ(2, CompileRun("o0_mirror.property('z').value().value()")
4695 ->Int32Value(context)
4696 .FromJust());
4697 CHECK(CompileRun("o0_mirror.property('u').isUndefined()")
4698 ->BooleanValue(context)
4699 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004700
4701 // The prototype (__proto__) for o0 should be o3 as o1 and o2 are hidden.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004702 CHECK(CompileRun("o0_mirror.protoObject() == o3_mirror")
4703 ->BooleanValue(context)
4704 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004705}
4706
4707
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004708static void ProtperyXNativeGetter(
4709 v8::Local<v8::String> property,
4710 const v8::PropertyCallbackInfo<v8::Value>& info) {
4711 info.GetReturnValue().Set(10);
Steve Blocka7e24c12009-10-30 11:49:00 +00004712}
4713
4714
4715TEST(NativeGetterPropertyMirror) {
4716 // Create a V8 environment with debug access.
Steve Blocka7e24c12009-10-30 11:49:00 +00004717 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004718 v8::Isolate* isolate = env->GetIsolate();
4719 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004720 env.ExposeDebug();
4721
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004722 v8::Local<v8::Context> context = env.context();
4723 v8::Local<v8::String> name = v8_str(isolate, "x");
Steve Blocka7e24c12009-10-30 11:49:00 +00004724 // Create object with named accessor.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004725 v8::Local<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
4726 named->SetAccessor(name, &ProtperyXNativeGetter, NULL, v8::Local<v8::Value>(),
4727 v8::DEFAULT, v8::None);
Steve Blocka7e24c12009-10-30 11:49:00 +00004728
4729 // Create object with named property getter.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004730 CHECK(env->Global()
4731 ->Set(context, v8_str(isolate, "instance"),
4732 named->NewInstance(context).ToLocalChecked())
4733 .FromJust());
4734 CHECK_EQ(10, CompileRun("instance.x")->Int32Value(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004735
4736 // Get mirror for the object with property getter.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004737 CompileRun("var instance_mirror = debug.MakeMirror(instance);");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004738 CHECK(CompileRun("instance_mirror instanceof debug.ObjectMirror")
4739 ->BooleanValue(context)
4740 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004741
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004742 CompileRun("var named_names = instance_mirror.propertyNames();");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004743 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value(context).FromJust());
4744 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue(context).FromJust());
4745 CHECK(CompileRun("instance_mirror.property('x').value().isNumber()")
4746 ->BooleanValue(context)
4747 .FromJust());
4748 CHECK(CompileRun("instance_mirror.property('x').value().value() == 10")
4749 ->BooleanValue(context)
4750 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004751}
4752
4753
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004754static void ProtperyXNativeGetterThrowingError(
4755 v8::Local<v8::String> property,
4756 const v8::PropertyCallbackInfo<v8::Value>& info) {
4757 CompileRun("throw new Error('Error message');");
Steve Blocka7e24c12009-10-30 11:49:00 +00004758}
4759
4760
4761TEST(NativeGetterThrowingErrorPropertyMirror) {
4762 // Create a V8 environment with debug access.
Steve Blocka7e24c12009-10-30 11:49:00 +00004763 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004764 v8::Isolate* isolate = env->GetIsolate();
4765 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004766 env.ExposeDebug();
4767
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004768 v8::Local<v8::Context> context = env.context();
4769 v8::Local<v8::String> name = v8_str(isolate, "x");
Steve Blocka7e24c12009-10-30 11:49:00 +00004770 // Create object with named accessor.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004771 v8::Local<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004772 named->SetAccessor(name, &ProtperyXNativeGetterThrowingError, NULL,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004773 v8::Local<v8::Value>(), v8::DEFAULT, v8::None);
Steve Blocka7e24c12009-10-30 11:49:00 +00004774
4775 // Create object with named property getter.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004776 CHECK(env->Global()
4777 ->Set(context, v8_str(isolate, "instance"),
4778 named->NewInstance(context).ToLocalChecked())
4779 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004780
4781 // Get mirror for the object with property getter.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004782 CompileRun("var instance_mirror = debug.MakeMirror(instance);");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004783 CHECK(CompileRun("instance_mirror instanceof debug.ObjectMirror")
4784 ->BooleanValue(context)
4785 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004786 CompileRun("named_names = instance_mirror.propertyNames();");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004787 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value(context).FromJust());
4788 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue(context).FromJust());
4789 CHECK(CompileRun("instance_mirror.property('x').value().isError()")
4790 ->BooleanValue(context)
4791 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004792
4793 // Check that the message is that passed to the Error constructor.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004794 CHECK(
4795 CompileRun(
4796 "instance_mirror.property('x').value().message() == 'Error message'")
4797 ->BooleanValue(context)
4798 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004799}
4800
4801
Steve Blockd0582a62009-12-15 09:54:21 +00004802// Test that hidden properties object is not returned as an unnamed property
4803// among regular properties.
4804// See http://crbug.com/26491
4805TEST(NoHiddenProperties) {
4806 // Create a V8 environment with debug access.
Steve Blockd0582a62009-12-15 09:54:21 +00004807 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004808 v8::Isolate* isolate = env->GetIsolate();
4809 v8::HandleScope scope(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +00004810 env.ExposeDebug();
4811
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004812 v8::Local<v8::Context> context = env.context();
Steve Blockd0582a62009-12-15 09:54:21 +00004813 // Create an object in the global scope.
4814 const char* source = "var obj = {a: 1};";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004815 v8::Script::Compile(context, v8_str(isolate, source))
4816 .ToLocalChecked()
4817 ->Run(context)
4818 .ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00004819 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004820 env->Global()->Get(context, v8_str(isolate, "obj")).ToLocalChecked());
Steve Blockd0582a62009-12-15 09:54:21 +00004821 // Set a hidden property on the object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004822 obj->SetPrivate(
4823 env.context(),
4824 v8::Private::New(isolate, v8_str(isolate, "v8::test-debug::a")),
4825 v8::Int32::New(isolate, 11))
4826 .FromJust();
Steve Blockd0582a62009-12-15 09:54:21 +00004827
4828 // Get mirror for the object with property getter.
4829 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004830 CHECK(CompileRun("obj_mirror instanceof debug.ObjectMirror")
4831 ->BooleanValue(context)
4832 .FromJust());
Steve Blockd0582a62009-12-15 09:54:21 +00004833 CompileRun("var named_names = obj_mirror.propertyNames();");
4834 // There should be exactly one property. But there is also an unnamed
4835 // property whose value is hidden properties dictionary. The latter
4836 // property should not be in the list of reguar properties.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004837 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value(context).FromJust());
4838 CHECK(CompileRun("named_names[0] == 'a'")->BooleanValue(context).FromJust());
4839 CHECK(CompileRun("obj_mirror.property('a').value().value() == 1")
4840 ->BooleanValue(context)
4841 .FromJust());
Steve Blockd0582a62009-12-15 09:54:21 +00004842
4843 // Object created by t0 will become hidden prototype of object 'obj'.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004844 v8::Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
4845 t0->InstanceTemplate()->Set(v8_str(isolate, "b"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004846 v8::Number::New(isolate, 2));
Steve Blockd0582a62009-12-15 09:54:21 +00004847 t0->SetHiddenPrototype(true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004848 v8::Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
4849 t1->InstanceTemplate()->Set(v8_str(isolate, "c"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004850 v8::Number::New(isolate, 3));
Steve Blockd0582a62009-12-15 09:54:21 +00004851
4852 // Create proto objects, add hidden properties to them and set them on
4853 // the global object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004854 v8::Local<v8::Object> protoObj = t0->GetFunction(context)
4855 .ToLocalChecked()
4856 ->NewInstance(context)
4857 .ToLocalChecked();
4858 protoObj->SetPrivate(
4859 env.context(),
4860 v8::Private::New(isolate, v8_str(isolate, "v8::test-debug::b")),
4861 v8::Int32::New(isolate, 12))
4862 .FromJust();
4863 CHECK(env->Global()
4864 ->Set(context, v8_str(isolate, "protoObj"), protoObj)
4865 .FromJust());
4866 v8::Local<v8::Object> grandProtoObj = t1->GetFunction(context)
4867 .ToLocalChecked()
4868 ->NewInstance(context)
4869 .ToLocalChecked();
4870 grandProtoObj->SetPrivate(env.context(),
4871 v8::Private::New(
4872 isolate, v8_str(isolate, "v8::test-debug::c")),
4873 v8::Int32::New(isolate, 13))
4874 .FromJust();
4875 CHECK(env->Global()
4876 ->Set(context, v8_str(isolate, "grandProtoObj"), grandProtoObj)
4877 .FromJust());
Steve Blockd0582a62009-12-15 09:54:21 +00004878
4879 // Setting prototypes: obj->protoObj->grandProtoObj
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004880 CHECK(protoObj->Set(context, v8_str(isolate, "__proto__"), grandProtoObj)
4881 .FromJust());
4882 CHECK(obj->Set(context, v8_str(isolate, "__proto__"), protoObj).FromJust());
Steve Blockd0582a62009-12-15 09:54:21 +00004883
4884 // Get mirror for the object with property getter.
4885 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004886 CHECK(CompileRun("obj_mirror instanceof debug.ObjectMirror")
4887 ->BooleanValue(context)
4888 .FromJust());
Steve Blockd0582a62009-12-15 09:54:21 +00004889 CompileRun("var named_names = obj_mirror.propertyNames();");
4890 // There should be exactly two properties - one from the object itself and
4891 // another from its hidden prototype.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004892 CHECK_EQ(2, CompileRun("named_names.length")->Int32Value(context).FromJust());
Steve Blockd0582a62009-12-15 09:54:21 +00004893 CHECK(CompileRun("named_names.sort(); named_names[0] == 'a' &&"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004894 "named_names[1] == 'b'")
4895 ->BooleanValue(context)
4896 .FromJust());
4897 CHECK(CompileRun("obj_mirror.property('a').value().value() == 1")
4898 ->BooleanValue(context)
4899 .FromJust());
4900 CHECK(CompileRun("obj_mirror.property('b').value().value() == 2")
4901 ->BooleanValue(context)
4902 .FromJust());
Steve Blockd0582a62009-12-15 09:54:21 +00004903}
4904
Steve Blocka7e24c12009-10-30 11:49:00 +00004905
4906// Multithreaded tests of JSON debugger protocol
4907
4908// Support classes
4909
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004910// Provides synchronization between N threads, where N is a template parameter.
4911// The Wait() call blocks a thread until it is called for the Nth time, then all
4912// calls return. Each ThreadBarrier object can only be used once.
4913template <int N>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004914class ThreadBarrier final {
Steve Blocka7e24c12009-10-30 11:49:00 +00004915 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004916 ThreadBarrier() : num_blocked_(0) {}
4917
4918 ~ThreadBarrier() {
4919 LockGuard<Mutex> lock_guard(&mutex_);
4920 if (num_blocked_ != 0) {
4921 CHECK_EQ(N, num_blocked_);
4922 }
4923 }
4924
4925 void Wait() {
4926 LockGuard<Mutex> lock_guard(&mutex_);
4927 CHECK_LT(num_blocked_, N);
4928 num_blocked_++;
4929 if (N == num_blocked_) {
4930 // Signal and unblock all waiting threads.
4931 cv_.NotifyAll();
4932 printf("BARRIER\n\n");
4933 fflush(stdout);
4934 } else { // Wait for the semaphore.
4935 while (num_blocked_ < N) {
4936 cv_.Wait(&mutex_);
4937 }
4938 }
4939 CHECK_EQ(N, num_blocked_);
4940 }
4941
Steve Blocka7e24c12009-10-30 11:49:00 +00004942 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004943 ConditionVariable cv_;
4944 Mutex mutex_;
Steve Blocka7e24c12009-10-30 11:49:00 +00004945 int num_blocked_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004946
4947 STATIC_ASSERT(N > 0);
4948
4949 DISALLOW_COPY_AND_ASSIGN(ThreadBarrier);
Steve Blocka7e24c12009-10-30 11:49:00 +00004950};
4951
Steve Blocka7e24c12009-10-30 11:49:00 +00004952
4953// A set containing enough barriers and semaphores for any of the tests.
4954class Barriers {
4955 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004956 Barriers() : semaphore_1(0), semaphore_2(0) {}
4957 ThreadBarrier<2> barrier_1;
4958 ThreadBarrier<2> barrier_2;
4959 ThreadBarrier<2> barrier_3;
4960 ThreadBarrier<2> barrier_4;
4961 ThreadBarrier<2> barrier_5;
4962 v8::base::Semaphore semaphore_1;
4963 v8::base::Semaphore semaphore_2;
Steve Blocka7e24c12009-10-30 11:49:00 +00004964};
4965
Steve Blocka7e24c12009-10-30 11:49:00 +00004966
4967// We match parts of the message to decide if it is a break message.
4968bool IsBreakEventMessage(char *message) {
4969 const char* type_event = "\"type\":\"event\"";
4970 const char* event_break = "\"event\":\"break\"";
4971 // Does the message contain both type:event and event:break?
4972 return strstr(message, type_event) != NULL &&
4973 strstr(message, event_break) != NULL;
4974}
4975
4976
Steve Block3ce2e202009-11-05 08:53:23 +00004977// We match parts of the message to decide if it is a exception message.
4978bool IsExceptionEventMessage(char *message) {
4979 const char* type_event = "\"type\":\"event\"";
4980 const char* event_exception = "\"event\":\"exception\"";
4981 // Does the message contain both type:event and event:exception?
4982 return strstr(message, type_event) != NULL &&
4983 strstr(message, event_exception) != NULL;
4984}
4985
4986
4987// We match the message wether it is an evaluate response message.
4988bool IsEvaluateResponseMessage(char* message) {
4989 const char* type_response = "\"type\":\"response\"";
4990 const char* command_evaluate = "\"command\":\"evaluate\"";
4991 // Does the message contain both type:response and command:evaluate?
4992 return strstr(message, type_response) != NULL &&
4993 strstr(message, command_evaluate) != NULL;
4994}
4995
4996
Andrei Popescu402d9372010-02-26 13:31:12 +00004997static int StringToInt(const char* s) {
4998 return atoi(s); // NOLINT
4999}
5000
5001
Steve Block3ce2e202009-11-05 08:53:23 +00005002// We match parts of the message to get evaluate result int value.
5003int GetEvaluateIntResult(char *message) {
5004 const char* value = "\"value\":";
5005 char* pos = strstr(message, value);
5006 if (pos == NULL) {
5007 return -1;
5008 }
5009 int res = -1;
Andrei Popescu402d9372010-02-26 13:31:12 +00005010 res = StringToInt(pos + strlen(value));
Steve Block3ce2e202009-11-05 08:53:23 +00005011 return res;
5012}
5013
5014
5015// We match parts of the message to get hit breakpoint id.
5016int GetBreakpointIdFromBreakEventMessage(char *message) {
5017 const char* breakpoints = "\"breakpoints\":[";
5018 char* pos = strstr(message, breakpoints);
5019 if (pos == NULL) {
5020 return -1;
5021 }
5022 int res = -1;
Andrei Popescu402d9372010-02-26 13:31:12 +00005023 res = StringToInt(pos + strlen(breakpoints));
Steve Block3ce2e202009-11-05 08:53:23 +00005024 return res;
5025}
5026
5027
Leon Clarked91b9f72010-01-27 17:25:45 +00005028// We match parts of the message to get total frames number.
5029int GetTotalFramesInt(char *message) {
5030 const char* prefix = "\"totalFrames\":";
5031 char* pos = strstr(message, prefix);
5032 if (pos == NULL) {
5033 return -1;
5034 }
5035 pos += strlen(prefix);
Andrei Popescu402d9372010-02-26 13:31:12 +00005036 int res = StringToInt(pos);
Leon Clarked91b9f72010-01-27 17:25:45 +00005037 return res;
5038}
5039
5040
Iain Merrick9ac36c92010-09-13 15:29:50 +01005041// We match parts of the message to get source line.
5042int GetSourceLineFromBreakEventMessage(char *message) {
5043 const char* source_line = "\"sourceLine\":";
5044 char* pos = strstr(message, source_line);
5045 if (pos == NULL) {
5046 return -1;
5047 }
5048 int res = -1;
5049 res = StringToInt(pos + strlen(source_line));
5050 return res;
5051}
5052
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005053
Steve Blocka7e24c12009-10-30 11:49:00 +00005054/* Test MessageQueues */
5055/* Tests the message queues that hold debugger commands and
5056 * response messages to the debugger. Fills queues and makes
5057 * them grow.
5058 */
5059Barriers message_queue_barriers;
5060
5061// This is the debugger thread, that executes no v8 calls except
5062// placing JSON debugger commands in the queue.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005063class MessageQueueDebuggerThread : public v8::base::Thread {
Steve Blocka7e24c12009-10-30 11:49:00 +00005064 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005065 MessageQueueDebuggerThread()
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005066 : Thread(Options("MessageQueueDebuggerThread")) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00005067 void Run();
5068};
5069
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005070
5071static void MessageHandler(const v8::Debug::Message& message) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005072 v8::Local<v8::String> json = message.GetJSON();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005073 v8::String::Utf8Value utf8(json);
5074 if (IsBreakEventMessage(*utf8)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005075 // Lets test script wait until break occurs to send commands.
5076 // Signals when a break is reported.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005077 message_queue_barriers.semaphore_2.Signal();
Steve Blocka7e24c12009-10-30 11:49:00 +00005078 }
5079
5080 // Allow message handler to block on a semaphore, to test queueing of
5081 // messages while blocked.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005082 message_queue_barriers.semaphore_1.Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +00005083}
5084
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005085
Steve Blocka7e24c12009-10-30 11:49:00 +00005086void MessageQueueDebuggerThread::Run() {
5087 const int kBufferSize = 1000;
5088 uint16_t buffer_1[kBufferSize];
5089 uint16_t buffer_2[kBufferSize];
5090 const char* command_1 =
5091 "{\"seq\":117,"
5092 "\"type\":\"request\","
5093 "\"command\":\"evaluate\","
5094 "\"arguments\":{\"expression\":\"1+2\"}}";
5095 const char* command_2 =
5096 "{\"seq\":118,"
5097 "\"type\":\"request\","
5098 "\"command\":\"evaluate\","
5099 "\"arguments\":{\"expression\":\"1+a\"}}";
5100 const char* command_3 =
5101 "{\"seq\":119,"
5102 "\"type\":\"request\","
5103 "\"command\":\"evaluate\","
5104 "\"arguments\":{\"expression\":\"c.d * b\"}}";
5105 const char* command_continue =
5106 "{\"seq\":106,"
5107 "\"type\":\"request\","
5108 "\"command\":\"continue\"}";
5109 const char* command_single_step =
5110 "{\"seq\":107,"
5111 "\"type\":\"request\","
5112 "\"command\":\"continue\","
5113 "\"arguments\":{\"stepaction\":\"next\"}}";
5114
5115 /* Interleaved sequence of actions by the two threads:*/
5116 // Main thread compiles and runs source_1
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005117 message_queue_barriers.semaphore_1.Signal();
Steve Blocka7e24c12009-10-30 11:49:00 +00005118 message_queue_barriers.barrier_1.Wait();
5119 // Post 6 commands, filling the command queue and making it expand.
5120 // These calls return immediately, but the commands stay on the queue
5121 // until the execution of source_2.
5122 // Note: AsciiToUtf16 executes before SendCommand, so command is copied
5123 // to buffer before buffer is sent to SendCommand.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005124 v8::Isolate* isolate = CcTest::isolate();
5125 v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_1, buffer_1));
5126 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_2, buffer_2));
5127 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
5128 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
5129 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00005130 message_queue_barriers.barrier_2.Wait();
5131 // Main thread compiles and runs source_2.
5132 // Queued commands are executed at the start of compilation of source_2(
5133 // beforeCompile event).
5134 // Free the message handler to process all the messages from the queue. 7
5135 // messages are expected: 2 afterCompile events and 5 responses.
5136 // All the commands added so far will fail to execute as long as call stack
5137 // is empty on beforeCompile event.
5138 for (int i = 0; i < 6 ; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005139 message_queue_barriers.semaphore_1.Signal();
Steve Blocka7e24c12009-10-30 11:49:00 +00005140 }
5141 message_queue_barriers.barrier_3.Wait();
5142 // Main thread compiles and runs source_3.
5143 // Don't stop in the afterCompile handler.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005144 message_queue_barriers.semaphore_1.Signal();
Steve Blocka7e24c12009-10-30 11:49:00 +00005145 // source_3 includes a debugger statement, which causes a break event.
5146 // Wait on break event from hitting "debugger" statement
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005147 message_queue_barriers.semaphore_2.Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +00005148 // These should execute after the "debugger" statement in source_2
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005149 v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_1, buffer_1));
5150 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_2, buffer_2));
5151 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
5152 v8::Debug::SendCommand(
5153 isolate, buffer_2, AsciiToUtf16(command_single_step, buffer_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00005154 // Run after 2 break events, 4 responses.
5155 for (int i = 0; i < 6 ; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005156 message_queue_barriers.semaphore_1.Signal();
Steve Blocka7e24c12009-10-30 11:49:00 +00005157 }
5158 // Wait on break event after a single step executes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005159 message_queue_barriers.semaphore_2.Wait();
5160 v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_2, buffer_1));
5161 v8::Debug::SendCommand(
5162 isolate, buffer_2, AsciiToUtf16(command_continue, buffer_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00005163 // Run after 2 responses.
5164 for (int i = 0; i < 2 ; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005165 message_queue_barriers.semaphore_1.Signal();
Steve Blocka7e24c12009-10-30 11:49:00 +00005166 }
5167 // Main thread continues running source_3 to end, waits for this thread.
5168}
5169
Steve Blocka7e24c12009-10-30 11:49:00 +00005170
5171// This thread runs the v8 engine.
5172TEST(MessageQueues) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005173 MessageQueueDebuggerThread message_queue_debugger_thread;
Steve Block44f0eee2011-05-26 01:26:41 +01005174
Steve Blocka7e24c12009-10-30 11:49:00 +00005175 // Create a V8 environment
Steve Blocka7e24c12009-10-30 11:49:00 +00005176 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005177 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005178 v8::Debug::SetMessageHandler(env->GetIsolate(), MessageHandler);
Steve Blocka7e24c12009-10-30 11:49:00 +00005179 message_queue_debugger_thread.Start();
5180
5181 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
5182 const char* source_2 = "e = 17;";
5183 const char* source_3 = "a = 4; debugger; a = 5; a = 6; a = 7;";
5184
5185 // See MessageQueueDebuggerThread::Run for interleaved sequence of
5186 // API calls and events in the two threads.
5187 CompileRun(source_1);
5188 message_queue_barriers.barrier_1.Wait();
5189 message_queue_barriers.barrier_2.Wait();
5190 CompileRun(source_2);
5191 message_queue_barriers.barrier_3.Wait();
5192 CompileRun(source_3);
5193 message_queue_debugger_thread.Join();
5194 fflush(stdout);
5195}
5196
5197
5198class TestClientData : public v8::Debug::ClientData {
5199 public:
5200 TestClientData() {
5201 constructor_call_counter++;
5202 }
5203 virtual ~TestClientData() {
5204 destructor_call_counter++;
5205 }
5206
5207 static void ResetCounters() {
5208 constructor_call_counter = 0;
5209 destructor_call_counter = 0;
5210 }
5211
5212 static int constructor_call_counter;
5213 static int destructor_call_counter;
5214};
5215
5216int TestClientData::constructor_call_counter = 0;
5217int TestClientData::destructor_call_counter = 0;
5218
5219
5220// Tests that MessageQueue doesn't destroy client data when expands and
5221// does destroy when it dies.
5222TEST(MessageQueueExpandAndDestroy) {
5223 TestClientData::ResetCounters();
5224 { // Create a scope for the queue.
5225 CommandMessageQueue queue(1);
5226 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5227 new TestClientData()));
5228 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5229 new TestClientData()));
5230 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5231 new TestClientData()));
5232 CHECK_EQ(0, TestClientData::destructor_call_counter);
5233 queue.Get().Dispose();
5234 CHECK_EQ(1, TestClientData::destructor_call_counter);
5235 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5236 new TestClientData()));
5237 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5238 new TestClientData()));
5239 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5240 new TestClientData()));
5241 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5242 new TestClientData()));
5243 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5244 new TestClientData()));
5245 CHECK_EQ(1, TestClientData::destructor_call_counter);
5246 queue.Get().Dispose();
5247 CHECK_EQ(2, TestClientData::destructor_call_counter);
5248 }
5249 // All the client data should be destroyed when the queue is destroyed.
5250 CHECK_EQ(TestClientData::destructor_call_counter,
5251 TestClientData::destructor_call_counter);
5252}
5253
5254
5255static int handled_client_data_instances_count = 0;
5256static void MessageHandlerCountingClientData(
5257 const v8::Debug::Message& message) {
5258 if (message.GetClientData() != NULL) {
5259 handled_client_data_instances_count++;
5260 }
5261}
5262
5263
5264// Tests that all client data passed to the debugger are sent to the handler.
5265TEST(SendClientDataToHandler) {
5266 // Create a V8 environment
Steve Blocka7e24c12009-10-30 11:49:00 +00005267 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005268 v8::Isolate* isolate = env->GetIsolate();
5269 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005270 TestClientData::ResetCounters();
5271 handled_client_data_instances_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005272 v8::Debug::SetMessageHandler(isolate, MessageHandlerCountingClientData);
Steve Blocka7e24c12009-10-30 11:49:00 +00005273 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
5274 const int kBufferSize = 1000;
5275 uint16_t buffer[kBufferSize];
5276 const char* command_1 =
5277 "{\"seq\":117,"
5278 "\"type\":\"request\","
5279 "\"command\":\"evaluate\","
5280 "\"arguments\":{\"expression\":\"1+2\"}}";
5281 const char* command_2 =
5282 "{\"seq\":118,"
5283 "\"type\":\"request\","
5284 "\"command\":\"evaluate\","
5285 "\"arguments\":{\"expression\":\"1+a\"}}";
5286 const char* command_continue =
5287 "{\"seq\":106,"
5288 "\"type\":\"request\","
5289 "\"command\":\"continue\"}";
5290
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005291 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_1, buffer),
Steve Blocka7e24c12009-10-30 11:49:00 +00005292 new TestClientData());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005293 v8::Debug::SendCommand(
5294 isolate, buffer, AsciiToUtf16(command_2, buffer), NULL);
5295 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_2, buffer),
Steve Blocka7e24c12009-10-30 11:49:00 +00005296 new TestClientData());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005297 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_2, buffer),
Steve Blocka7e24c12009-10-30 11:49:00 +00005298 new TestClientData());
5299 // All the messages will be processed on beforeCompile event.
5300 CompileRun(source_1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005301 v8::Debug::SendCommand(
5302 isolate, buffer, AsciiToUtf16(command_continue, buffer));
Steve Blocka7e24c12009-10-30 11:49:00 +00005303 CHECK_EQ(3, TestClientData::constructor_call_counter);
5304 CHECK_EQ(TestClientData::constructor_call_counter,
5305 handled_client_data_instances_count);
5306 CHECK_EQ(TestClientData::constructor_call_counter,
5307 TestClientData::destructor_call_counter);
5308}
5309
5310
5311/* Test ThreadedDebugging */
5312/* This test interrupts a running infinite loop that is
5313 * occupying the v8 thread by a break command from the
5314 * debugger thread. It then changes the value of a
5315 * global object, to make the loop terminate.
5316 */
5317
5318Barriers threaded_debugging_barriers;
5319
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005320class V8Thread : public v8::base::Thread {
Steve Blocka7e24c12009-10-30 11:49:00 +00005321 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005322 V8Thread() : Thread(Options("V8Thread")) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00005323 void Run();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005324 v8::Isolate* isolate() { return isolate_; }
5325
5326 private:
5327 v8::Isolate* isolate_;
Steve Blocka7e24c12009-10-30 11:49:00 +00005328};
5329
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005330class DebuggerThread : public v8::base::Thread {
Steve Blocka7e24c12009-10-30 11:49:00 +00005331 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005332 explicit DebuggerThread(v8::Isolate* isolate)
5333 : Thread(Options("DebuggerThread")), isolate_(isolate) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00005334 void Run();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005335
5336 private:
5337 v8::Isolate* isolate_;
Steve Blocka7e24c12009-10-30 11:49:00 +00005338};
5339
5340
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005341static void ThreadedAtBarrier1(
5342 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005343 threaded_debugging_barriers.barrier_1.Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +00005344}
5345
5346
5347static void ThreadedMessageHandler(const v8::Debug::Message& message) {
5348 static char print_buffer[1000];
5349 v8::String::Value json(message.GetJSON());
5350 Utf16ToAscii(*json, json.length(), print_buffer);
5351 if (IsBreakEventMessage(print_buffer)) {
Iain Merrick9ac36c92010-09-13 15:29:50 +01005352 // Check that we are inside the while loop.
5353 int source_line = GetSourceLineFromBreakEventMessage(print_buffer);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005354 CHECK(4 <= source_line && source_line <= 10);
Steve Blocka7e24c12009-10-30 11:49:00 +00005355 threaded_debugging_barriers.barrier_2.Wait();
5356 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005357}
5358
5359
5360void V8Thread::Run() {
5361 const char* source =
5362 "flag = true;\n"
Steve Blocka7e24c12009-10-30 11:49:00 +00005363 "\n"
5364 "function foo() {\n"
5365 " var x = 1;\n"
5366 " while ( flag == true ) {\n"
5367 " if ( x == 1 ) {\n"
5368 " ThreadedAtBarrier1();\n"
5369 " }\n"
5370 " x = x + 1;\n"
5371 " }\n"
5372 "}\n"
5373 "\n"
5374 "foo();\n";
5375
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005376 v8::Isolate::CreateParams create_params;
5377 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
5378 isolate_ = v8::Isolate::New(create_params);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005379 threaded_debugging_barriers.barrier_3.Wait();
5380 {
5381 v8::Isolate::Scope isolate_scope(isolate_);
5382 DebugLocalContext env(isolate_);
5383 v8::HandleScope scope(isolate_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005384 v8::Debug::SetMessageHandler(isolate_, &ThreadedMessageHandler);
5385 v8::Local<v8::ObjectTemplate> global_template =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005386 v8::ObjectTemplate::New(env->GetIsolate());
5387 global_template->Set(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005388 v8_str(env->GetIsolate(), "ThreadedAtBarrier1"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005389 v8::FunctionTemplate::New(isolate_, ThreadedAtBarrier1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005390 v8::Local<v8::Context> context =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005391 v8::Context::New(isolate_, NULL, global_template);
5392 v8::Context::Scope context_scope(context);
Steve Blocka7e24c12009-10-30 11:49:00 +00005393
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005394 CompileRun(source);
5395 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005396 threaded_debugging_barriers.barrier_4.Wait();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005397 isolate_->Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +00005398}
5399
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005400
Steve Blocka7e24c12009-10-30 11:49:00 +00005401void DebuggerThread::Run() {
5402 const int kBufSize = 1000;
5403 uint16_t buffer[kBufSize];
5404
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005405 const char* command_1 =
5406 "{\"seq\":102,"
Steve Blocka7e24c12009-10-30 11:49:00 +00005407 "\"type\":\"request\","
5408 "\"command\":\"evaluate\","
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005409 "\"arguments\":{\"expression\":\"flag = false\"}}";
Steve Blocka7e24c12009-10-30 11:49:00 +00005410 const char* command_2 = "{\"seq\":103,"
5411 "\"type\":\"request\","
5412 "\"command\":\"continue\"}";
5413
5414 threaded_debugging_barriers.barrier_1.Wait();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005415 v8::Debug::DebugBreak(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00005416 threaded_debugging_barriers.barrier_2.Wait();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005417 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_1, buffer));
5418 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_2, buffer));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005419 threaded_debugging_barriers.barrier_4.Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +00005420}
5421
Steve Blocka7e24c12009-10-30 11:49:00 +00005422
5423TEST(ThreadedDebugging) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005424 V8Thread v8_thread;
Steve Block44f0eee2011-05-26 01:26:41 +01005425
Steve Blocka7e24c12009-10-30 11:49:00 +00005426 // Create a V8 environment
Steve Blocka7e24c12009-10-30 11:49:00 +00005427 v8_thread.Start();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005428 threaded_debugging_barriers.barrier_3.Wait();
5429 DebuggerThread debugger_thread(v8_thread.isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005430 debugger_thread.Start();
5431
5432 v8_thread.Join();
5433 debugger_thread.Join();
5434}
5435
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005436
Steve Blocka7e24c12009-10-30 11:49:00 +00005437/* Test RecursiveBreakpoints */
5438/* In this test, the debugger evaluates a function with a breakpoint, after
5439 * hitting a breakpoint in another function. We do this with both values
5440 * of the flag enabling recursive breakpoints, and verify that the second
5441 * breakpoint is hit when enabled, and missed when disabled.
5442 */
5443
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005444class BreakpointsV8Thread : public v8::base::Thread {
Steve Blocka7e24c12009-10-30 11:49:00 +00005445 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005446 BreakpointsV8Thread() : Thread(Options("BreakpointsV8Thread")) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00005447 void Run();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005448
5449 v8::Isolate* isolate() { return isolate_; }
5450
5451 private:
5452 v8::Isolate* isolate_;
Steve Blocka7e24c12009-10-30 11:49:00 +00005453};
5454
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005455class BreakpointsDebuggerThread : public v8::base::Thread {
Steve Blocka7e24c12009-10-30 11:49:00 +00005456 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005457 BreakpointsDebuggerThread(bool global_evaluate, v8::Isolate* isolate)
5458 : Thread(Options("BreakpointsDebuggerThread")),
5459 global_evaluate_(global_evaluate),
5460 isolate_(isolate) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00005461 void Run();
Leon Clarked91b9f72010-01-27 17:25:45 +00005462
5463 private:
5464 bool global_evaluate_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005465 v8::Isolate* isolate_;
Steve Blocka7e24c12009-10-30 11:49:00 +00005466};
5467
5468
5469Barriers* breakpoints_barriers;
Steve Block3ce2e202009-11-05 08:53:23 +00005470int break_event_breakpoint_id;
5471int evaluate_int_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00005472
5473static void BreakpointsMessageHandler(const v8::Debug::Message& message) {
5474 static char print_buffer[1000];
5475 v8::String::Value json(message.GetJSON());
5476 Utf16ToAscii(*json, json.length(), print_buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00005477
Steve Blocka7e24c12009-10-30 11:49:00 +00005478 if (IsBreakEventMessage(print_buffer)) {
Steve Block3ce2e202009-11-05 08:53:23 +00005479 break_event_breakpoint_id =
5480 GetBreakpointIdFromBreakEventMessage(print_buffer);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005481 breakpoints_barriers->semaphore_1.Signal();
Steve Block3ce2e202009-11-05 08:53:23 +00005482 } else if (IsEvaluateResponseMessage(print_buffer)) {
5483 evaluate_int_result = GetEvaluateIntResult(print_buffer);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005484 breakpoints_barriers->semaphore_1.Signal();
Steve Blocka7e24c12009-10-30 11:49:00 +00005485 }
5486}
5487
5488
5489void BreakpointsV8Thread::Run() {
5490 const char* source_1 = "var y_global = 3;\n"
5491 "function cat( new_value ) {\n"
5492 " var x = new_value;\n"
Steve Block3ce2e202009-11-05 08:53:23 +00005493 " y_global = y_global + 4;\n"
Steve Blocka7e24c12009-10-30 11:49:00 +00005494 " x = 3 * x + 1;\n"
Steve Block3ce2e202009-11-05 08:53:23 +00005495 " y_global = y_global + 5;\n"
Steve Blocka7e24c12009-10-30 11:49:00 +00005496 " return x;\n"
5497 "}\n"
5498 "\n"
5499 "function dog() {\n"
5500 " var x = 1;\n"
5501 " x = y_global;"
5502 " var z = 3;"
5503 " x += 100;\n"
5504 " return x;\n"
5505 "}\n"
5506 "\n";
5507 const char* source_2 = "cat(17);\n"
5508 "cat(19);\n";
5509
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005510 v8::Isolate::CreateParams create_params;
5511 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
5512 isolate_ = v8::Isolate::New(create_params);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005513 breakpoints_barriers->barrier_3.Wait();
5514 {
5515 v8::Isolate::Scope isolate_scope(isolate_);
5516 DebugLocalContext env(isolate_);
5517 v8::HandleScope scope(isolate_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005518 v8::Debug::SetMessageHandler(isolate_, &BreakpointsMessageHandler);
Steve Blocka7e24c12009-10-30 11:49:00 +00005519
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005520 CompileRun(source_1);
5521 breakpoints_barriers->barrier_1.Wait();
5522 breakpoints_barriers->barrier_2.Wait();
5523 CompileRun(source_2);
5524 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005525 breakpoints_barriers->barrier_4.Wait();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005526 isolate_->Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +00005527}
5528
5529
5530void BreakpointsDebuggerThread::Run() {
5531 const int kBufSize = 1000;
5532 uint16_t buffer[kBufSize];
5533
5534 const char* command_1 = "{\"seq\":101,"
5535 "\"type\":\"request\","
5536 "\"command\":\"setbreakpoint\","
5537 "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}";
5538 const char* command_2 = "{\"seq\":102,"
5539 "\"type\":\"request\","
5540 "\"command\":\"setbreakpoint\","
5541 "\"arguments\":{\"type\":\"function\",\"target\":\"dog\",\"line\":3}}";
Leon Clarked91b9f72010-01-27 17:25:45 +00005542 const char* command_3;
5543 if (this->global_evaluate_) {
5544 command_3 = "{\"seq\":103,"
5545 "\"type\":\"request\","
5546 "\"command\":\"evaluate\","
5547 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false,"
5548 "\"global\":true}}";
5549 } else {
5550 command_3 = "{\"seq\":103,"
5551 "\"type\":\"request\","
5552 "\"command\":\"evaluate\","
5553 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false}}";
5554 }
5555 const char* command_4;
5556 if (this->global_evaluate_) {
5557 command_4 = "{\"seq\":104,"
5558 "\"type\":\"request\","
5559 "\"command\":\"evaluate\","
5560 "\"arguments\":{\"expression\":\"100 + 8\",\"disable_break\":true,"
5561 "\"global\":true}}";
5562 } else {
5563 command_4 = "{\"seq\":104,"
5564 "\"type\":\"request\","
5565 "\"command\":\"evaluate\","
5566 "\"arguments\":{\"expression\":\"x + 1\",\"disable_break\":true}}";
5567 }
Steve Block3ce2e202009-11-05 08:53:23 +00005568 const char* command_5 = "{\"seq\":105,"
Steve Blocka7e24c12009-10-30 11:49:00 +00005569 "\"type\":\"request\","
5570 "\"command\":\"continue\"}";
Steve Block3ce2e202009-11-05 08:53:23 +00005571 const char* command_6 = "{\"seq\":106,"
Steve Blocka7e24c12009-10-30 11:49:00 +00005572 "\"type\":\"request\","
5573 "\"command\":\"continue\"}";
Leon Clarked91b9f72010-01-27 17:25:45 +00005574 const char* command_7;
5575 if (this->global_evaluate_) {
5576 command_7 = "{\"seq\":107,"
5577 "\"type\":\"request\","
5578 "\"command\":\"evaluate\","
5579 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true,"
5580 "\"global\":true}}";
5581 } else {
5582 command_7 = "{\"seq\":107,"
5583 "\"type\":\"request\","
5584 "\"command\":\"evaluate\","
5585 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true}}";
5586 }
Steve Block3ce2e202009-11-05 08:53:23 +00005587 const char* command_8 = "{\"seq\":108,"
Steve Blocka7e24c12009-10-30 11:49:00 +00005588 "\"type\":\"request\","
5589 "\"command\":\"continue\"}";
5590
5591
5592 // v8 thread initializes, runs source_1
5593 breakpoints_barriers->barrier_1.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005594 // 1:Set breakpoint in cat() (will get id 1).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005595 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_1, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005596 // 2:Set breakpoint in dog() (will get id 2).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005597 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_2, buffer));
Steve Blocka7e24c12009-10-30 11:49:00 +00005598 breakpoints_barriers->barrier_2.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005599 // V8 thread starts compiling source_2.
Steve Blocka7e24c12009-10-30 11:49:00 +00005600 // Automatic break happens, to run queued commands
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005601 // breakpoints_barriers->semaphore_1.Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +00005602 // Commands 1 through 3 run, thread continues.
5603 // v8 thread runs source_2 to breakpoint in cat().
5604 // message callback receives break event.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005605 breakpoints_barriers->semaphore_1.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005606 // Must have hit breakpoint #1.
5607 CHECK_EQ(1, break_event_breakpoint_id);
Steve Blocka7e24c12009-10-30 11:49:00 +00005608 // 4:Evaluate dog() (which has a breakpoint).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005609 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_3, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005610 // V8 thread hits breakpoint in dog().
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005611 breakpoints_barriers->semaphore_1.Wait(); // wait for break event
Steve Block3ce2e202009-11-05 08:53:23 +00005612 // Must have hit breakpoint #2.
5613 CHECK_EQ(2, break_event_breakpoint_id);
5614 // 5:Evaluate (x + 1).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005615 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_4, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005616 // Evaluate (x + 1) finishes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005617 breakpoints_barriers->semaphore_1.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005618 // Must have result 108.
5619 CHECK_EQ(108, evaluate_int_result);
5620 // 6:Continue evaluation of dog().
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005621 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_5, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005622 // Evaluate dog() finishes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005623 breakpoints_barriers->semaphore_1.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005624 // Must have result 107.
5625 CHECK_EQ(107, evaluate_int_result);
Steve Blocka7e24c12009-10-30 11:49:00 +00005626 // 7:Continue evaluation of source_2, finish cat(17), hit breakpoint
5627 // in cat(19).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005628 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_6, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005629 // Message callback gets break event.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005630 breakpoints_barriers->semaphore_1.Wait(); // wait for break event
Steve Block3ce2e202009-11-05 08:53:23 +00005631 // Must have hit breakpoint #1.
5632 CHECK_EQ(1, break_event_breakpoint_id);
5633 // 8: Evaluate dog() with breaks disabled.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005634 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_7, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005635 // Evaluate dog() finishes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005636 breakpoints_barriers->semaphore_1.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005637 // Must have result 116.
5638 CHECK_EQ(116, evaluate_int_result);
Steve Blocka7e24c12009-10-30 11:49:00 +00005639 // 9: Continue evaluation of source2, reach end.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005640 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_8, buffer));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005641 breakpoints_barriers->barrier_4.Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +00005642}
5643
Leon Clarke888f6722010-01-27 15:57:47 +00005644
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005645void TestRecursiveBreakpointsGeneric(bool global_evaluate) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005646 BreakpointsV8Thread breakpoints_v8_thread;
Leon Clarked91b9f72010-01-27 17:25:45 +00005647
Steve Blocka7e24c12009-10-30 11:49:00 +00005648 // Create a V8 environment
5649 Barriers stack_allocated_breakpoints_barriers;
Steve Blocka7e24c12009-10-30 11:49:00 +00005650 breakpoints_barriers = &stack_allocated_breakpoints_barriers;
5651
5652 breakpoints_v8_thread.Start();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005653 breakpoints_barriers->barrier_3.Wait();
5654 BreakpointsDebuggerThread breakpoints_debugger_thread(
5655 global_evaluate, breakpoints_v8_thread.isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005656 breakpoints_debugger_thread.Start();
5657
5658 breakpoints_v8_thread.Join();
5659 breakpoints_debugger_thread.Join();
5660}
5661
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005662
Leon Clarked91b9f72010-01-27 17:25:45 +00005663TEST(RecursiveBreakpoints) {
5664 TestRecursiveBreakpointsGeneric(false);
5665}
5666
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005667
Leon Clarked91b9f72010-01-27 17:25:45 +00005668TEST(RecursiveBreakpointsGlobal) {
5669 TestRecursiveBreakpointsGeneric(true);
5670}
5671
Steve Blocka7e24c12009-10-30 11:49:00 +00005672
Steve Blocka7e24c12009-10-30 11:49:00 +00005673TEST(SetDebugEventListenerOnUninitializedVM) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005674 v8::Debug::SetDebugEventListener(CcTest::isolate(), DummyDebugEventListener);
Steve Blocka7e24c12009-10-30 11:49:00 +00005675}
5676
5677
5678static void DummyMessageHandler(const v8::Debug::Message& message) {
5679}
5680
5681
5682TEST(SetMessageHandlerOnUninitializedVM) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005683 v8::Debug::SetMessageHandler(CcTest::isolate(), DummyMessageHandler);
Steve Blocka7e24c12009-10-30 11:49:00 +00005684}
5685
5686
5687// Source for a JavaScript function which returns the data parameter of a
5688// function called in the context of the debugger. If no data parameter is
5689// passed it throws an exception.
5690static const char* debugger_call_with_data_source =
5691 "function debugger_call_with_data(exec_state, data) {"
5692 " if (data) return data;"
5693 " throw 'No data!'"
5694 "}";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005695v8::Local<v8::Function> debugger_call_with_data;
Steve Blocka7e24c12009-10-30 11:49:00 +00005696
5697
5698// Source for a JavaScript function which returns the data parameter of a
5699// function called in the context of the debugger. If no data parameter is
5700// passed it throws an exception.
5701static const char* debugger_call_with_closure_source =
5702 "var x = 3;"
5703 "(function (exec_state) {"
5704 " if (exec_state.y) return x - 1;"
5705 " exec_state.y = x;"
5706 " return exec_state.y"
5707 "})";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005708v8::Local<v8::Function> debugger_call_with_closure;
Steve Blocka7e24c12009-10-30 11:49:00 +00005709
5710// Function to retrieve the number of JavaScript frames by calling a JavaScript
5711// in the debugger.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005712static void CheckFrameCount(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005713 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
5714 CHECK(v8::Debug::Call(context, frame_count).ToLocalChecked()->IsNumber());
5715 CHECK_EQ(args[0]->Int32Value(context).FromJust(),
5716 v8::Debug::Call(context, frame_count)
5717 .ToLocalChecked()
5718 ->Int32Value(context)
5719 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00005720}
5721
5722
5723// Function to retrieve the source line of the top JavaScript frame by calling a
5724// JavaScript function in the debugger.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005725static void CheckSourceLine(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005726 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
5727 CHECK(
5728 v8::Debug::Call(context, frame_source_line).ToLocalChecked()->IsNumber());
5729 CHECK_EQ(args[0]->Int32Value(context).FromJust(),
5730 v8::Debug::Call(context, frame_source_line)
5731 .ToLocalChecked()
5732 ->Int32Value(context)
5733 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00005734}
5735
5736
5737// Function to test passing an additional parameter to a JavaScript function
5738// called in the debugger. It also tests that functions called in the debugger
5739// can throw exceptions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005740static void CheckDataParameter(
5741 const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005742 v8::Local<v8::String> data = v8_str(args.GetIsolate(), "Test");
5743 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
5744 CHECK(v8::Debug::Call(context, debugger_call_with_data, data)
5745 .ToLocalChecked()
5746 ->IsString());
Steve Blocka7e24c12009-10-30 11:49:00 +00005747
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005748 for (int i = 0; i < 3; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005749 v8::TryCatch catcher(args.GetIsolate());
5750 CHECK(v8::Debug::Call(context, debugger_call_with_data).IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005751 CHECK(catcher.HasCaught());
5752 CHECK(catcher.Exception()->IsString());
5753 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005754}
5755
5756
5757// Function to test using a JavaScript with closure in the debugger.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005758static void CheckClosure(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005759 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
5760 CHECK(v8::Debug::Call(context, debugger_call_with_closure)
5761 .ToLocalChecked()
5762 ->IsNumber());
5763 CHECK_EQ(3, v8::Debug::Call(context, debugger_call_with_closure)
5764 .ToLocalChecked()
5765 ->Int32Value(context)
5766 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00005767}
5768
5769
5770// Test functions called through the debugger.
5771TEST(CallFunctionInDebugger) {
5772 // Create and enter a context with the functions CheckFrameCount,
5773 // CheckSourceLine and CheckDataParameter installed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005774 v8::Isolate* isolate = CcTest::isolate();
5775 v8::HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005776 v8::Local<v8::ObjectTemplate> global_template =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005777 v8::ObjectTemplate::New(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005778 global_template->Set(v8_str(isolate, "CheckFrameCount"),
5779 v8::FunctionTemplate::New(isolate, CheckFrameCount));
5780 global_template->Set(v8_str(isolate, "CheckSourceLine"),
5781 v8::FunctionTemplate::New(isolate, CheckSourceLine));
5782 global_template->Set(v8_str(isolate, "CheckDataParameter"),
5783 v8::FunctionTemplate::New(isolate, CheckDataParameter));
5784 global_template->Set(v8_str(isolate, "CheckClosure"),
5785 v8::FunctionTemplate::New(isolate, CheckClosure));
5786 v8::Local<v8::Context> context =
5787 v8::Context::New(isolate, NULL, global_template);
Steve Blocka7e24c12009-10-30 11:49:00 +00005788 v8::Context::Scope context_scope(context);
5789
5790 // Compile a function for checking the number of JavaScript frames.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005791 v8::Script::Compile(context, v8_str(isolate, frame_count_source))
5792 .ToLocalChecked()
5793 ->Run(context)
5794 .ToLocalChecked();
5795 frame_count = v8::Local<v8::Function>::Cast(
5796 context->Global()
5797 ->Get(context, v8_str(isolate, "frame_count"))
5798 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00005799
5800 // Compile a function for returning the source line for the top frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005801 v8::Script::Compile(context, v8_str(isolate, frame_source_line_source))
5802 .ToLocalChecked()
5803 ->Run(context)
5804 .ToLocalChecked();
5805 frame_source_line = v8::Local<v8::Function>::Cast(
5806 context->Global()
5807 ->Get(context, v8_str(isolate, "frame_source_line"))
5808 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00005809
5810 // Compile a function returning the data parameter.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005811 v8::Script::Compile(context, v8_str(isolate, debugger_call_with_data_source))
5812 .ToLocalChecked()
5813 ->Run(context)
5814 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005815 debugger_call_with_data = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005816 context->Global()
5817 ->Get(context, v8_str(isolate, "debugger_call_with_data"))
5818 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00005819
5820 // Compile a function capturing closure.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005821 debugger_call_with_closure = v8::Local<v8::Function>::Cast(
5822 v8::Script::Compile(context,
5823 v8_str(isolate, debugger_call_with_closure_source))
5824 .ToLocalChecked()
5825 ->Run(context)
5826 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00005827
Steve Block6ded16b2010-05-10 14:33:55 +01005828 // Calling a function through the debugger returns 0 frames if there are
5829 // no JavaScript frames.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005830 CHECK(v8::Integer::New(isolate, 0)
5831 ->Equals(context,
5832 v8::Debug::Call(context, frame_count).ToLocalChecked())
5833 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00005834
5835 // Test that the number of frames can be retrieved.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005836 v8::Script::Compile(context, v8_str(isolate, "CheckFrameCount(1)"))
5837 .ToLocalChecked()
5838 ->Run(context)
5839 .ToLocalChecked();
5840 v8::Script::Compile(context, v8_str(isolate,
5841 "function f() {"
5842 " CheckFrameCount(2);"
5843 "}; f()"))
5844 .ToLocalChecked()
5845 ->Run(context)
5846 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005847
5848 // Test that the source line can be retrieved.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005849 v8::Script::Compile(context, v8_str(isolate, "CheckSourceLine(0)"))
5850 .ToLocalChecked()
5851 ->Run(context)
5852 .ToLocalChecked();
5853 v8::Script::Compile(context, v8_str(isolate,
5854 "function f() {\n"
5855 " CheckSourceLine(1)\n"
5856 " CheckSourceLine(2)\n"
5857 " CheckSourceLine(3)\n"
5858 "}; f()"))
5859 .ToLocalChecked()
5860 ->Run(context)
5861 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005862
5863 // Test that a parameter can be passed to a function called in the debugger.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005864 v8::Script::Compile(context, v8_str(isolate, "CheckDataParameter()"))
5865 .ToLocalChecked()
5866 ->Run(context)
5867 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005868
5869 // Test that a function with closure can be run in the debugger.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005870 v8::Script::Compile(context, v8_str(isolate, "CheckClosure()"))
5871 .ToLocalChecked()
5872 ->Run(context)
5873 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005874
5875 // Test that the source line is correct when there is a line offset.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005876 v8::ScriptOrigin origin(v8_str(isolate, "test"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005877 v8::Integer::New(isolate, 7));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005878 v8::Script::Compile(context, v8_str(isolate, "CheckSourceLine(7)"), &origin)
5879 .ToLocalChecked()
5880 ->Run(context)
5881 .ToLocalChecked();
5882 v8::Script::Compile(context, v8_str(isolate,
5883 "function f() {\n"
5884 " CheckSourceLine(8)\n"
5885 " CheckSourceLine(9)\n"
5886 " CheckSourceLine(10)\n"
5887 "}; f()"),
5888 &origin)
5889 .ToLocalChecked()
5890 ->Run(context)
5891 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005892}
5893
5894
5895// Debugger message handler which counts the number of breaks.
5896static void SendContinueCommand();
5897static void MessageHandlerBreakPointHitCount(
5898 const v8::Debug::Message& message) {
5899 if (message.IsEvent() && message.GetEvent() == v8::Break) {
5900 // Count the number of breaks.
5901 break_point_hit_count++;
5902
5903 SendContinueCommand();
5904 }
5905}
5906
5907
5908// Test that clearing the debug event listener actually clears all break points
5909// and related information.
5910TEST(DebuggerUnload) {
5911 DebugLocalContext env;
5912
5913 // Check debugger is unloaded before it is used.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005914 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005915
5916 // Set a debug event listener.
5917 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005918 v8::Debug::SetDebugEventListener(env->GetIsolate(),
5919 DebugEventBreakPointHitCount);
5920 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00005921 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005922 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005923 // Create a couple of functions for the test.
5924 v8::Local<v8::Function> foo =
5925 CompileFunction(&env, "function foo(){x=1}", "foo");
5926 v8::Local<v8::Function> bar =
5927 CompileFunction(&env, "function bar(){y=2}", "bar");
5928
5929 // Set some break points.
5930 SetBreakPoint(foo, 0);
5931 SetBreakPoint(foo, 4);
5932 SetBreakPoint(bar, 0);
5933 SetBreakPoint(bar, 4);
5934
5935 // Make sure that the break points are there.
5936 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005937 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005938 CHECK_EQ(2, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005939 bar->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005940 CHECK_EQ(4, break_point_hit_count);
5941 }
5942
5943 // Remove the debug event listener without clearing breakpoints. Do this
5944 // outside a handle scope.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005945 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
5946 CheckDebuggerUnloaded(env->GetIsolate(), true);
Steve Blocka7e24c12009-10-30 11:49:00 +00005947
5948 // Now set a debug message handler.
5949 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005950 v8::Debug::SetMessageHandler(env->GetIsolate(),
5951 MessageHandlerBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00005952 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005953 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005954
5955 // Get the test functions again.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005956 v8::Local<v8::Function> foo(v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005957 env->Global()
5958 ->Get(context, v8_str(env->GetIsolate(), "foo"))
5959 .ToLocalChecked()));
Steve Blocka7e24c12009-10-30 11:49:00 +00005960
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005961 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005962 CHECK_EQ(0, break_point_hit_count);
5963
5964 // Set break points and run again.
5965 SetBreakPoint(foo, 0);
5966 SetBreakPoint(foo, 4);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005967 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005968 CHECK_EQ(2, break_point_hit_count);
5969 }
5970
5971 // Remove the debug message handler without clearing breakpoints. Do this
5972 // outside a handle scope.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005973 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
5974 CheckDebuggerUnloaded(env->GetIsolate(), true);
Steve Blocka7e24c12009-10-30 11:49:00 +00005975}
5976
5977
5978// Sends continue command to the debugger.
5979static void SendContinueCommand() {
5980 const int kBufferSize = 1000;
5981 uint16_t buffer[kBufferSize];
5982 const char* command_continue =
5983 "{\"seq\":0,"
5984 "\"type\":\"request\","
5985 "\"command\":\"continue\"}";
5986
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005987 v8::Debug::SendCommand(
5988 CcTest::isolate(), buffer, AsciiToUtf16(command_continue, buffer));
Steve Blocka7e24c12009-10-30 11:49:00 +00005989}
5990
5991
5992// Debugger message handler which counts the number of times it is called.
5993static int message_handler_hit_count = 0;
5994static void MessageHandlerHitCount(const v8::Debug::Message& message) {
5995 message_handler_hit_count++;
5996
Steve Block3ce2e202009-11-05 08:53:23 +00005997 static char print_buffer[1000];
5998 v8::String::Value json(message.GetJSON());
5999 Utf16ToAscii(*json, json.length(), print_buffer);
6000 if (IsExceptionEventMessage(print_buffer)) {
6001 // Send a continue command for exception events.
6002 SendContinueCommand();
6003 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006004}
6005
6006
6007// Test clearing the debug message handler.
6008TEST(DebuggerClearMessageHandler) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006009 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006010 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006011
6012 // Check debugger is unloaded before it is used.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006013 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006014
6015 // Set a debug message handler.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006016 v8::Debug::SetMessageHandler(env->GetIsolate(), MessageHandlerHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00006017
6018 // Run code to throw a unhandled exception. This should end up in the message
6019 // handler.
6020 CompileRun("throw 1");
6021
6022 // The message handler should be called.
6023 CHECK_GT(message_handler_hit_count, 0);
6024
6025 // Clear debug message handler.
6026 message_handler_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006027 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
Steve Blocka7e24c12009-10-30 11:49:00 +00006028
6029 // Run code to throw a unhandled exception. This should end up in the message
6030 // handler.
6031 CompileRun("throw 1");
6032
6033 // The message handler should not be called more.
6034 CHECK_EQ(0, message_handler_hit_count);
6035
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006036 CheckDebuggerUnloaded(env->GetIsolate(), true);
Steve Blocka7e24c12009-10-30 11:49:00 +00006037}
6038
6039
6040// Debugger message handler which clears the message handler while active.
6041static void MessageHandlerClearingMessageHandler(
6042 const v8::Debug::Message& message) {
6043 message_handler_hit_count++;
6044
6045 // Clear debug message handler.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006046 v8::Debug::SetMessageHandler(message.GetIsolate(), nullptr);
Steve Blocka7e24c12009-10-30 11:49:00 +00006047}
6048
6049
6050// Test clearing the debug message handler while processing a debug event.
6051TEST(DebuggerClearMessageHandlerWhileActive) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006052 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006053 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006054
6055 // Check debugger is unloaded before it is used.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006056 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006057
6058 // Set a debug message handler.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006059 v8::Debug::SetMessageHandler(env->GetIsolate(),
6060 MessageHandlerClearingMessageHandler);
Steve Blocka7e24c12009-10-30 11:49:00 +00006061
6062 // Run code to throw a unhandled exception. This should end up in the message
6063 // handler.
6064 CompileRun("throw 1");
6065
6066 // The message handler should be called.
6067 CHECK_EQ(1, message_handler_hit_count);
6068
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006069 CheckDebuggerUnloaded(env->GetIsolate(), true);
Steve Blocka7e24c12009-10-30 11:49:00 +00006070}
6071
6072
Steve Blocka7e24c12009-10-30 11:49:00 +00006073// Test for issue http://code.google.com/p/v8/issues/detail?id=289.
6074// Make sure that DebugGetLoadedScripts doesn't return scripts
6075// with disposed external source.
6076class EmptyExternalStringResource : public v8::String::ExternalStringResource {
6077 public:
6078 EmptyExternalStringResource() { empty_[0] = 0; }
6079 virtual ~EmptyExternalStringResource() {}
6080 virtual size_t length() const { return empty_.length(); }
6081 virtual const uint16_t* data() const { return empty_.start(); }
6082 private:
6083 ::v8::internal::EmbeddedVector<uint16_t, 1> empty_;
6084};
6085
6086
6087TEST(DebugGetLoadedScripts) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006088 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006089 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006090 env.ExposeDebug();
6091
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006092 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00006093 EmptyExternalStringResource source_ext_str;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006094 v8::Local<v8::String> source =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006095 v8::String::NewExternalTwoByte(env->GetIsolate(), &source_ext_str)
6096 .ToLocalChecked();
6097 CHECK(v8::Script::Compile(context, source).IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00006098 Handle<i::ExternalTwoByteString> i_source(
6099 i::ExternalTwoByteString::cast(*v8::Utils::OpenHandle(*source)));
6100 // This situation can happen if source was an external string disposed
6101 // by its owner.
6102 i_source->set_resource(0);
6103
6104 bool allow_natives_syntax = i::FLAG_allow_natives_syntax;
6105 i::FLAG_allow_natives_syntax = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006106 EnableDebugger(env->GetIsolate());
6107 v8::MaybeLocal<v8::Value> result =
6108 CompileRun(env.context(),
6109 "var scripts = %DebugGetLoadedScripts();"
6110 "var count = scripts.length;"
6111 "for (var i = 0; i < count; ++i) {"
6112 " var lines = scripts[i].lineCount();"
6113 " if (lines < 1) throw 'lineCount';"
6114 " var last = -1;"
6115 " for (var j = 0; j < lines; ++j) {"
6116 " var end = scripts[i].lineEnd(j);"
6117 " if (last >= end) throw 'lineEnd';"
6118 " last = end;"
6119 " }"
6120 "}");
6121 CHECK(!result.IsEmpty());
6122 DisableDebugger(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006123 // Must not crash while accessing line_ends.
6124 i::FLAG_allow_natives_syntax = allow_natives_syntax;
6125
6126 // Some scripts are retrieved - at least the number of native scripts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006127 CHECK_GT(env->Global()
6128 ->Get(context, v8_str(env->GetIsolate(), "count"))
6129 .ToLocalChecked()
6130 ->Int32Value(context)
6131 .FromJust(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006132 8);
Steve Blocka7e24c12009-10-30 11:49:00 +00006133}
6134
6135
6136// Test script break points set on lines.
6137TEST(ScriptNameAndData) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006138 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006139 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006140 env.ExposeDebug();
6141
6142 // Create functions for retrieving script name and data for the function on
6143 // the top frame when hitting a break point.
6144 frame_script_name = CompileFunction(&env,
6145 frame_script_name_source,
6146 "frame_script_name");
Steve Blocka7e24c12009-10-30 11:49:00 +00006147
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006148 v8::Debug::SetDebugEventListener(env->GetIsolate(),
6149 DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00006150
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006151 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00006152 // Test function source.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006153 v8::Local<v8::String> script = v8_str(env->GetIsolate(),
6154 "function f() {\n"
6155 " debugger;\n"
6156 "}\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00006157
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006158 v8::ScriptOrigin origin1 =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006159 v8::ScriptOrigin(v8_str(env->GetIsolate(), "name"));
6160 v8::Local<v8::Script> script1 =
6161 v8::Script::Compile(context, script, &origin1).ToLocalChecked();
6162 script1->Run(context).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006163 v8::Local<v8::Function> f;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006164 f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006165 env->Global()
6166 ->Get(context, v8_str(env->GetIsolate(), "f"))
6167 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00006168
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006169 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006170 CHECK_EQ(1, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006171 CHECK_EQ(0, strcmp("name", last_script_name_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00006172
6173 // Compile the same script again without setting data. As the compilation
6174 // cache is disabled when debugging expect the data to be missing.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006175 v8::Script::Compile(context, script, &origin1)
6176 .ToLocalChecked()
6177 ->Run(context)
6178 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006179 f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006180 env->Global()
6181 ->Get(context, v8_str(env->GetIsolate(), "f"))
6182 .ToLocalChecked());
6183 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006184 CHECK_EQ(2, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006185 CHECK_EQ(0, strcmp("name", last_script_name_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00006186
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006187 v8::Local<v8::String> data_obj_source =
6188 v8_str(env->GetIsolate(),
6189 "({ a: 'abc',\n"
6190 " b: 123,\n"
6191 " toString: function() { return this.a + ' ' + this.b; }\n"
6192 "})\n");
6193 v8::Script::Compile(context, data_obj_source)
6194 .ToLocalChecked()
6195 ->Run(context)
6196 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006197 v8::ScriptOrigin origin2 =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006198 v8::ScriptOrigin(v8_str(env->GetIsolate(), "new name"));
6199 v8::Local<v8::Script> script2 =
6200 v8::Script::Compile(context, script, &origin2).ToLocalChecked();
6201 script2->Run(context).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006202 f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006203 env->Global()
6204 ->Get(context, v8_str(env->GetIsolate(), "f"))
6205 .ToLocalChecked());
6206 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006207 CHECK_EQ(3, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006208 CHECK_EQ(0, strcmp("new name", last_script_name_hit));
Andrei Popescu402d9372010-02-26 13:31:12 +00006209
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006210 v8::Local<v8::Script> script3 =
6211 v8::Script::Compile(context, script, &origin2).ToLocalChecked();
6212 script3->Run(context).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006213 f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006214 env->Global()
6215 ->Get(context, v8_str(env->GetIsolate(), "f"))
6216 .ToLocalChecked());
6217 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Andrei Popescu402d9372010-02-26 13:31:12 +00006218 CHECK_EQ(4, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00006219}
6220
6221
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006222static v8::Local<v8::Context> expected_context;
6223static v8::Local<v8::Value> expected_context_data;
Steve Blocka7e24c12009-10-30 11:49:00 +00006224
6225
6226// Check that the expected context is the one generating the debug event.
6227static void ContextCheckMessageHandler(const v8::Debug::Message& message) {
6228 CHECK(message.GetEventContext() == expected_context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006229 CHECK(message.GetEventContext()->GetEmbedderData(0)->StrictEquals(
Steve Blocka7e24c12009-10-30 11:49:00 +00006230 expected_context_data));
6231 message_handler_hit_count++;
6232
Steve Block3ce2e202009-11-05 08:53:23 +00006233 static char print_buffer[1000];
6234 v8::String::Value json(message.GetJSON());
6235 Utf16ToAscii(*json, json.length(), print_buffer);
6236
Steve Blocka7e24c12009-10-30 11:49:00 +00006237 // Send a continue command for break events.
Steve Block3ce2e202009-11-05 08:53:23 +00006238 if (IsBreakEventMessage(print_buffer)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006239 SendContinueCommand();
6240 }
6241}
6242
6243
6244// Test which creates two contexts and sets different embedder data on each.
6245// Checks that this data is set correctly and that when the debug message
6246// handler is called the expected context is the one active.
6247TEST(ContextData) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006248 v8::Isolate* isolate = CcTest::isolate();
6249 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006250
6251 // Create two contexts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006252 v8::Local<v8::Context> context_1;
6253 v8::Local<v8::Context> context_2;
6254 v8::Local<v8::ObjectTemplate> global_template =
6255 v8::Local<v8::ObjectTemplate>();
6256 v8::Local<v8::Value> global_object = v8::Local<v8::Value>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006257 context_1 = v8::Context::New(isolate, NULL, global_template, global_object);
6258 context_2 = v8::Context::New(isolate, NULL, global_template, global_object);
6259
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006260 v8::Debug::SetMessageHandler(isolate, ContextCheckMessageHandler);
Steve Blocka7e24c12009-10-30 11:49:00 +00006261
6262 // Default data value is undefined.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006263 CHECK(context_1->GetEmbedderData(0)->IsUndefined());
6264 CHECK(context_2->GetEmbedderData(0)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00006265
6266 // Set and check different data values.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006267 v8::Local<v8::String> data_1 = v8_str(isolate, "1");
6268 v8::Local<v8::String> data_2 = v8_str(isolate, "2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006269 context_1->SetEmbedderData(0, data_1);
6270 context_2->SetEmbedderData(0, data_2);
6271 CHECK(context_1->GetEmbedderData(0)->StrictEquals(data_1));
6272 CHECK(context_2->GetEmbedderData(0)->StrictEquals(data_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00006273
6274 // Simple test function which causes a break.
6275 const char* source = "function f() { debugger; }";
6276
6277 // Enter and run function in the first context.
6278 {
6279 v8::Context::Scope context_scope(context_1);
6280 expected_context = context_1;
6281 expected_context_data = data_1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006282 v8::Local<v8::Function> f = CompileFunction(isolate, source, "f");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006283 f->Call(context_1, context_1->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006284 }
6285
6286
6287 // Enter and run function in the second context.
6288 {
6289 v8::Context::Scope context_scope(context_2);
6290 expected_context = context_2;
6291 expected_context_data = data_2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006292 v8::Local<v8::Function> f = CompileFunction(isolate, source, "f");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006293 f->Call(context_2, context_2->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006294 }
6295
6296 // Two times compile event and two times break event.
6297 CHECK_GT(message_handler_hit_count, 4);
6298
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006299 v8::Debug::SetMessageHandler(isolate, nullptr);
6300 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006301}
6302
6303
6304// Debug message handler which issues a debug break when it hits a break event.
6305static int message_handler_break_hit_count = 0;
6306static void DebugBreakMessageHandler(const v8::Debug::Message& message) {
6307 // Schedule a debug break for break events.
6308 if (message.IsEvent() && message.GetEvent() == v8::Break) {
6309 message_handler_break_hit_count++;
6310 if (message_handler_break_hit_count == 1) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006311 v8::Debug::DebugBreak(message.GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006312 }
6313 }
6314
6315 // Issue a continue command if this event will not cause the VM to start
6316 // running.
6317 if (!message.WillStartRunning()) {
6318 SendContinueCommand();
6319 }
6320}
6321
6322
6323// Test that a debug break can be scheduled while in a message handler.
6324TEST(DebugBreakInMessageHandler) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006325 i::FLAG_turbo_inlining = false; // Make sure g is not inlined into f.
Steve Blocka7e24c12009-10-30 11:49:00 +00006326 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006327 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006328
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006329 v8::Debug::SetMessageHandler(env->GetIsolate(), DebugBreakMessageHandler);
Steve Blocka7e24c12009-10-30 11:49:00 +00006330
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006331 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00006332 // Test functions.
6333 const char* script = "function f() { debugger; g(); } function g() { }";
6334 CompileRun(script);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006335 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006336 env->Global()
6337 ->Get(context, v8_str(env->GetIsolate(), "f"))
6338 .ToLocalChecked());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006339 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006340 env->Global()
6341 ->Get(context, v8_str(env->GetIsolate(), "g"))
6342 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00006343
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006344 // Call f then g. The debugger statement in f will cause a break which will
Steve Blocka7e24c12009-10-30 11:49:00 +00006345 // cause another break.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006346 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006347 CHECK_EQ(2, message_handler_break_hit_count);
6348 // Calling g will not cause any additional breaks.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006349 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006350 CHECK_EQ(2, message_handler_break_hit_count);
6351}
6352
6353
Steve Block6ded16b2010-05-10 14:33:55 +01006354#ifndef V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +00006355// Debug event handler which gets the function on the top frame and schedules a
6356// break a number of times.
6357static void DebugEventDebugBreak(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006358 const v8::Debug::EventDetails& event_details) {
6359 v8::DebugEvent event = event_details.GetEvent();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006360 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
6361 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
Steve Blocka7e24c12009-10-30 11:49:00 +00006362 if (event == v8::Break) {
6363 break_point_hit_count++;
6364
6365 // Get the name of the top frame function.
6366 if (!frame_function_name.IsEmpty()) {
6367 // Get the name of the function.
Ben Murdochb0fe1622011-05-05 13:52:32 +01006368 const int argc = 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006369 v8::Local<v8::Value> argv[argc] = {
6370 exec_state, v8::Integer::New(CcTest::isolate(), 0)};
6371 v8::Local<v8::Value> result =
6372 frame_function_name->Call(context, exec_state, argc, argv)
6373 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006374 if (result->IsUndefined()) {
6375 last_function_hit[0] = '\0';
6376 } else {
6377 CHECK(result->IsString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006378 v8::Local<v8::String> function_name(
6379 result->ToString(context).ToLocalChecked());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006380 function_name->WriteUtf8(last_function_hit);
Steve Blocka7e24c12009-10-30 11:49:00 +00006381 }
6382 }
6383
6384 // Keep forcing breaks.
6385 if (break_point_hit_count < 20) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006386 v8::Debug::DebugBreak(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006387 }
6388 }
6389}
6390
6391
6392TEST(RegExpDebugBreak) {
6393 // This test only applies to native regexps.
Steve Blocka7e24c12009-10-30 11:49:00 +00006394 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006395 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006396 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00006397 // Create a function for checking the function when hitting a break point.
6398 frame_function_name = CompileFunction(&env,
6399 frame_function_name_source,
6400 "frame_function_name");
6401
6402 // Test RegExp which matches white spaces and comments at the begining of a
6403 // source line.
6404 const char* script =
6405 "var sourceLineBeginningSkip = /^(?:[ \\v\\h]*(?:\\/\\*.*?\\*\\/)*)*/;\n"
6406 "function f(s) { return s.match(sourceLineBeginningSkip)[0].length; }";
6407
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006408 v8::Local<v8::Function> f = CompileFunction(env->GetIsolate(), script, "f");
Steve Blocka7e24c12009-10-30 11:49:00 +00006409 const int argc = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006410 v8::Local<v8::Value> argv[argc] = {
6411 v8_str(env->GetIsolate(), " /* xxx */ a=0;")};
6412 v8::Local<v8::Value> result =
6413 f->Call(context, env->Global(), argc, argv).ToLocalChecked();
6414 CHECK_EQ(12, result->Int32Value(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00006415
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006416 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventDebugBreak);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006417 v8::Debug::DebugBreak(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006418 result = f->Call(context, env->Global(), argc, argv).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006419
6420 // Check that there was only one break event. Matching RegExp should not
6421 // cause Break events.
6422 CHECK_EQ(1, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006423 CHECK_EQ(0, strcmp("f", last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00006424}
Steve Block6ded16b2010-05-10 14:33:55 +01006425#endif // V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +00006426
6427
6428// Common part of EvalContextData and NestedBreakEventContextData tests.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006429static void ExecuteScriptForContextCheck(
6430 v8::Debug::MessageHandler message_handler) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006431 // Create a context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006432 v8::Local<v8::Context> context_1;
6433 v8::Local<v8::ObjectTemplate> global_template =
6434 v8::Local<v8::ObjectTemplate>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006435 context_1 =
6436 v8::Context::New(CcTest::isolate(), NULL, global_template);
6437
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006438 v8::Debug::SetMessageHandler(CcTest::isolate(), message_handler);
Steve Blocka7e24c12009-10-30 11:49:00 +00006439
6440 // Default data value is undefined.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006441 CHECK(context_1->GetEmbedderData(0)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00006442
6443 // Set and check a data value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006444 v8::Local<v8::String> data_1 = v8_str(CcTest::isolate(), "1");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006445 context_1->SetEmbedderData(0, data_1);
6446 CHECK(context_1->GetEmbedderData(0)->StrictEquals(data_1));
Steve Blocka7e24c12009-10-30 11:49:00 +00006447
6448 // Simple test function with eval that causes a break.
6449 const char* source = "function f() { eval('debugger;'); }";
6450
6451 // Enter and run function in the context.
6452 {
6453 v8::Context::Scope context_scope(context_1);
6454 expected_context = context_1;
6455 expected_context_data = data_1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006456 v8::Local<v8::Function> f = CompileFunction(CcTest::isolate(), source, "f");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006457 f->Call(context_1, context_1->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006458 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006459
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006460 v8::Debug::SetMessageHandler(CcTest::isolate(), nullptr);
Steve Blocka7e24c12009-10-30 11:49:00 +00006461}
6462
6463
6464// Test which creates a context and sets embedder data on it. Checks that this
6465// data is set correctly and that when the debug message handler is called for
6466// break event in an eval statement the expected context is the one returned by
6467// Message.GetEventContext.
6468TEST(EvalContextData) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006469 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006470
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006471 ExecuteScriptForContextCheck(ContextCheckMessageHandler);
Steve Blocka7e24c12009-10-30 11:49:00 +00006472
6473 // One time compile event and one time break event.
6474 CHECK_GT(message_handler_hit_count, 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006475 CheckDebuggerUnloaded(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006476}
6477
6478
6479static bool sent_eval = false;
6480static int break_count = 0;
6481static int continue_command_send_count = 0;
6482// Check that the expected context is the one generating the debug event
6483// including the case of nested break event.
6484static void DebugEvalContextCheckMessageHandler(
6485 const v8::Debug::Message& message) {
6486 CHECK(message.GetEventContext() == expected_context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006487 CHECK(message.GetEventContext()->GetEmbedderData(0)->StrictEquals(
Steve Blocka7e24c12009-10-30 11:49:00 +00006488 expected_context_data));
6489 message_handler_hit_count++;
6490
Steve Block3ce2e202009-11-05 08:53:23 +00006491 static char print_buffer[1000];
6492 v8::String::Value json(message.GetJSON());
6493 Utf16ToAscii(*json, json.length(), print_buffer);
6494
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006495 v8::Isolate* isolate = message.GetIsolate();
Steve Block3ce2e202009-11-05 08:53:23 +00006496 if (IsBreakEventMessage(print_buffer)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006497 break_count++;
6498 if (!sent_eval) {
6499 sent_eval = true;
6500
6501 const int kBufferSize = 1000;
6502 uint16_t buffer[kBufferSize];
6503 const char* eval_command =
Ben Murdoch257744e2011-11-30 15:57:28 +00006504 "{\"seq\":0,"
6505 "\"type\":\"request\","
6506 "\"command\":\"evaluate\","
6507 "\"arguments\":{\"expression\":\"debugger;\","
6508 "\"global\":true,\"disable_break\":false}}";
Steve Blocka7e24c12009-10-30 11:49:00 +00006509
6510 // Send evaluate command.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006511 v8::Debug::SendCommand(
6512 isolate, buffer, AsciiToUtf16(eval_command, buffer));
Steve Blocka7e24c12009-10-30 11:49:00 +00006513 return;
6514 } else {
6515 // It's a break event caused by the evaluation request above.
6516 SendContinueCommand();
6517 continue_command_send_count++;
6518 }
Steve Block3ce2e202009-11-05 08:53:23 +00006519 } else if (IsEvaluateResponseMessage(print_buffer) &&
6520 continue_command_send_count < 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006521 // Response to the evaluation request. We're still on the breakpoint so
6522 // send continue.
6523 SendContinueCommand();
6524 continue_command_send_count++;
6525 }
6526}
6527
6528
6529// Tests that context returned for break event is correct when the event occurs
6530// in 'evaluate' debugger request.
6531TEST(NestedBreakEventContextData) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006532 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006533 break_count = 0;
6534 message_handler_hit_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00006535
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006536 ExecuteScriptForContextCheck(DebugEvalContextCheckMessageHandler);
Steve Blocka7e24c12009-10-30 11:49:00 +00006537
6538 // One time compile event and two times break event.
6539 CHECK_GT(message_handler_hit_count, 3);
6540
6541 // One break from the source and another from the evaluate request.
6542 CHECK_EQ(break_count, 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006543 CheckDebuggerUnloaded(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006544}
6545
6546
Steve Blocka7e24c12009-10-30 11:49:00 +00006547// Debug event listener which counts the after compile events.
6548int after_compile_message_count = 0;
6549static void AfterCompileMessageHandler(const v8::Debug::Message& message) {
6550 // Count the number of scripts collected.
6551 if (message.IsEvent()) {
6552 if (message.GetEvent() == v8::AfterCompile) {
6553 after_compile_message_count++;
6554 } else if (message.GetEvent() == v8::Break) {
6555 SendContinueCommand();
6556 }
6557 }
6558}
6559
6560
6561// Tests that after compile event is sent as many times as there are scripts
6562// compiled.
6563TEST(AfterCompileMessageWhenMessageHandlerIsReset) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006564 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006565 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006566 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00006567 after_compile_message_count = 0;
6568 const char* script = "var a=1";
6569
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006570 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler);
6571 v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
6572 .ToLocalChecked()
6573 ->Run(context)
6574 .ToLocalChecked();
6575 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
Steve Blocka7e24c12009-10-30 11:49:00 +00006576
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006577 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006578 v8::Debug::DebugBreak(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006579 v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
6580 .ToLocalChecked()
6581 ->Run(context)
6582 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006583
6584 // Setting listener to NULL should cause debugger unload.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006585 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
6586 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006587
6588 // Compilation cache should be disabled when debugger is active.
6589 CHECK_EQ(2, after_compile_message_count);
6590}
6591
6592
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006593// Syntax error event handler which counts a number of events.
6594int compile_error_event_count = 0;
6595
6596static void CompileErrorEventCounterClear() {
6597 compile_error_event_count = 0;
6598}
6599
6600static void CompileErrorEventCounter(
6601 const v8::Debug::EventDetails& event_details) {
6602 v8::DebugEvent event = event_details.GetEvent();
6603
6604 if (event == v8::CompileError) {
6605 compile_error_event_count++;
6606 }
6607}
6608
6609
6610// Tests that syntax error event is sent as many times as there are scripts
6611// with syntax error compiled.
6612TEST(SyntaxErrorMessageOnSyntaxException) {
6613 DebugLocalContext env;
6614 v8::HandleScope scope(env->GetIsolate());
6615
6616 // For this test, we want to break on uncaught exceptions:
6617 ChangeBreakOnException(false, true);
6618
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006619 v8::Debug::SetDebugEventListener(env->GetIsolate(), CompileErrorEventCounter);
6620 v8::Local<v8::Context> context = env.context();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006621
6622 CompileErrorEventCounterClear();
6623
6624 // Check initial state.
6625 CHECK_EQ(0, compile_error_event_count);
6626
6627 // Throws SyntaxError: Unexpected end of input
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006628 CHECK(
6629 v8::Script::Compile(context, v8_str(env->GetIsolate(), "+++")).IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006630 CHECK_EQ(1, compile_error_event_count);
6631
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006632 CHECK(v8::Script::Compile(context, v8_str(env->GetIsolate(), "/sel\\/: \\"))
6633 .IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006634 CHECK_EQ(2, compile_error_event_count);
6635
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006636 v8::Local<v8::Script> script =
6637 v8::Script::Compile(context,
6638 v8_str(env->GetIsolate(), "JSON.parse('1234:')"))
6639 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006640 CHECK_EQ(2, compile_error_event_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006641 CHECK(script->Run(context).IsEmpty());
6642 CHECK_EQ(3, compile_error_event_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006643
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006644 v8::Script::Compile(context,
6645 v8_str(env->GetIsolate(), "new RegExp('/\\/\\\\');"))
6646 .ToLocalChecked();
6647 CHECK_EQ(3, compile_error_event_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006648
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006649 v8::Script::Compile(context, v8_str(env->GetIsolate(), "throw 1;"))
6650 .ToLocalChecked();
6651 CHECK_EQ(3, compile_error_event_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006652}
6653
6654
Steve Blocka7e24c12009-10-30 11:49:00 +00006655// Tests that break event is sent when message handler is reset.
6656TEST(BreakMessageWhenMessageHandlerIsReset) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006657 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006658 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006659 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00006660 after_compile_message_count = 0;
6661 const char* script = "function f() {};";
6662
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006663 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler);
6664 v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
6665 .ToLocalChecked()
6666 ->Run(context)
6667 .ToLocalChecked();
6668 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
Steve Blocka7e24c12009-10-30 11:49:00 +00006669
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006670 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006671 v8::Debug::DebugBreak(env->GetIsolate());
6672 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006673 env->Global()
6674 ->Get(context, v8_str(env->GetIsolate(), "f"))
6675 .ToLocalChecked());
6676 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006677
6678 // Setting message handler to NULL should cause debugger unload.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006679 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
6680 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006681
6682 // Compilation cache should be disabled when debugger is active.
6683 CHECK_EQ(1, after_compile_message_count);
6684}
6685
6686
6687static int exception_event_count = 0;
6688static void ExceptionMessageHandler(const v8::Debug::Message& message) {
6689 if (message.IsEvent() && message.GetEvent() == v8::Exception) {
6690 exception_event_count++;
6691 SendContinueCommand();
6692 }
6693}
6694
6695
6696// Tests that exception event is sent when message handler is reset.
6697TEST(ExceptionMessageWhenMessageHandlerIsReset) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006698 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006699 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch086aeea2011-05-13 15:57:08 +01006700
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006701 v8::Local<v8::Context> context = env.context();
Ben Murdoch086aeea2011-05-13 15:57:08 +01006702 // For this test, we want to break on uncaught exceptions:
6703 ChangeBreakOnException(false, true);
6704
Steve Blocka7e24c12009-10-30 11:49:00 +00006705 exception_event_count = 0;
6706 const char* script = "function f() {throw new Error()};";
6707
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006708 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler);
6709 v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
6710 .ToLocalChecked()
6711 ->Run(context)
6712 .ToLocalChecked();
6713 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
Steve Blocka7e24c12009-10-30 11:49:00 +00006714
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006715 v8::Debug::SetMessageHandler(env->GetIsolate(), ExceptionMessageHandler);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006716 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006717 env->Global()
6718 ->Get(context, v8_str(env->GetIsolate(), "f"))
6719 .ToLocalChecked());
6720 CHECK(f->Call(context, env->Global(), 0, NULL).IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00006721
6722 // Setting message handler to NULL should cause debugger unload.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006723 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
6724 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006725
6726 CHECK_EQ(1, exception_event_count);
6727}
6728
6729
6730// Tests after compile event is sent when there are some provisional
6731// breakpoints out of the scripts lines range.
6732TEST(ProvisionalBreakpointOnLineOutOfRange) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006733 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006734 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006735 env.ExposeDebug();
6736 const char* script = "function f() {};";
6737 const char* resource_name = "test_resource";
6738
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006739 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler);
6740 v8::Local<v8::Context> context = env.context();
6741
Steve Blocka7e24c12009-10-30 11:49:00 +00006742 // Set a couple of provisional breakpoint on lines out of the script lines
6743 // range.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006744 int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name,
6745 3, -1 /* no column */);
6746 int sbp2 =
6747 SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name, 5, 5);
Steve Blocka7e24c12009-10-30 11:49:00 +00006748
6749 after_compile_message_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00006750
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006751 v8::ScriptOrigin origin(v8_str(env->GetIsolate(), resource_name),
6752 v8::Integer::New(env->GetIsolate(), 10),
6753 v8::Integer::New(env->GetIsolate(), 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00006754 // Compile a script whose first line number is greater than the breakpoints'
6755 // lines.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006756 v8::Script::Compile(context, v8_str(env->GetIsolate(), script), &origin)
6757 .ToLocalChecked()
6758 ->Run(context)
6759 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006760
6761 // If the script is compiled successfully there is exactly one after compile
6762 // event. In case of an exception in debugger code after compile event is not
6763 // sent.
6764 CHECK_EQ(1, after_compile_message_count);
6765
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006766 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
6767 ClearBreakPointFromJS(env->GetIsolate(), sbp2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006768 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
Steve Blocka7e24c12009-10-30 11:49:00 +00006769}
6770
6771
6772static void BreakMessageHandler(const v8::Debug::Message& message) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006773 i::Isolate* isolate = CcTest::i_isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00006774 if (message.IsEvent() && message.GetEvent() == v8::Break) {
6775 // Count the number of breaks.
6776 break_point_hit_count++;
6777
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006778 i::HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006779 message.GetJSON();
Steve Blocka7e24c12009-10-30 11:49:00 +00006780
6781 SendContinueCommand();
6782 } else if (message.IsEvent() && message.GetEvent() == v8::AfterCompile) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006783 i::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006784
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006785 int current_count = break_point_hit_count;
Steve Blocka7e24c12009-10-30 11:49:00 +00006786
6787 // Force serialization to trigger some internal JS execution.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006788 message.GetJSON();
Steve Blocka7e24c12009-10-30 11:49:00 +00006789
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006790 CHECK_EQ(current_count, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00006791 }
6792}
6793
6794
6795// Test that if DebugBreak is forced it is ignored when code from
6796// debug-delay.js is executed.
6797TEST(NoDebugBreakInAfterCompileMessageHandler) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006798 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006799 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006800 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00006801
6802 // Register a debug event listener which sets the break flag and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006803 v8::Debug::SetMessageHandler(env->GetIsolate(), BreakMessageHandler);
Steve Blocka7e24c12009-10-30 11:49:00 +00006804
6805 // Set the debug break flag.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006806 v8::Debug::DebugBreak(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006807
6808 // Create a function for testing stepping.
6809 const char* src = "function f() { eval('var x = 10;'); } ";
6810 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
6811
6812 // There should be only one break event.
6813 CHECK_EQ(1, break_point_hit_count);
6814
6815 // Set the debug break flag again.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006816 v8::Debug::DebugBreak(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006817 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006818 // There should be one more break event when the script is evaluated in 'f'.
6819 CHECK_EQ(2, break_point_hit_count);
6820
6821 // Get rid of the debug message handler.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006822 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
6823 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006824}
6825
6826
Leon Clarkee46be812010-01-19 14:06:41 +00006827static int counting_message_handler_counter;
6828
6829static void CountingMessageHandler(const v8::Debug::Message& message) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006830 if (message.IsResponse()) counting_message_handler_counter++;
Leon Clarkee46be812010-01-19 14:06:41 +00006831}
6832
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006833
Leon Clarkee46be812010-01-19 14:06:41 +00006834// Test that debug messages get processed when ProcessDebugMessages is called.
6835TEST(ProcessDebugMessages) {
Leon Clarkee46be812010-01-19 14:06:41 +00006836 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006837 v8::Isolate* isolate = env->GetIsolate();
6838 v8::HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00006839
6840 counting_message_handler_counter = 0;
6841
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006842 v8::Debug::SetMessageHandler(isolate, CountingMessageHandler);
Leon Clarkee46be812010-01-19 14:06:41 +00006843
6844 const int kBufferSize = 1000;
6845 uint16_t buffer[kBufferSize];
6846 const char* scripts_command =
6847 "{\"seq\":0,"
6848 "\"type\":\"request\","
6849 "\"command\":\"scripts\"}";
6850
6851 // Send scripts command.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006852 v8::Debug::SendCommand(
6853 isolate, buffer, AsciiToUtf16(scripts_command, buffer));
Leon Clarkee46be812010-01-19 14:06:41 +00006854
6855 CHECK_EQ(0, counting_message_handler_counter);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006856 v8::Debug::ProcessDebugMessages(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00006857 // At least one message should come
6858 CHECK_GE(counting_message_handler_counter, 1);
6859
6860 counting_message_handler_counter = 0;
6861
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006862 v8::Debug::SendCommand(
6863 isolate, buffer, AsciiToUtf16(scripts_command, buffer));
6864 v8::Debug::SendCommand(
6865 isolate, buffer, AsciiToUtf16(scripts_command, buffer));
Leon Clarkee46be812010-01-19 14:06:41 +00006866 CHECK_EQ(0, counting_message_handler_counter);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006867 v8::Debug::ProcessDebugMessages(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00006868 // At least two messages should come
6869 CHECK_GE(counting_message_handler_counter, 2);
6870
6871 // Get rid of the debug message handler.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006872 v8::Debug::SetMessageHandler(isolate, nullptr);
6873 CheckDebuggerUnloaded(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006874}
6875
6876
6877class SendCommandThread;
6878static SendCommandThread* send_command_thread_ = NULL;
6879
6880
6881class SendCommandThread : public v8::base::Thread {
6882 public:
6883 explicit SendCommandThread(v8::Isolate* isolate)
6884 : Thread(Options("SendCommandThread")),
6885 semaphore_(0),
6886 isolate_(isolate) {}
6887
6888 static void CountingAndSignallingMessageHandler(
6889 const v8::Debug::Message& message) {
6890 if (message.IsResponse()) {
6891 counting_message_handler_counter++;
6892 send_command_thread_->semaphore_.Signal();
6893 }
6894 }
6895
6896 virtual void Run() {
6897 semaphore_.Wait();
6898 const int kBufferSize = 1000;
6899 uint16_t buffer[kBufferSize];
6900 const char* scripts_command =
6901 "{\"seq\":0,"
6902 "\"type\":\"request\","
6903 "\"command\":\"scripts\"}";
6904 int length = AsciiToUtf16(scripts_command, buffer);
6905 // Send scripts command.
6906
6907 for (int i = 0; i < 20; i++) {
6908 v8::base::ElapsedTimer timer;
6909 timer.Start();
6910 CHECK_EQ(i, counting_message_handler_counter);
6911 // Queue debug message.
6912 v8::Debug::SendCommand(isolate_, buffer, length);
6913 // Wait for the message handler to pick up the response.
6914 semaphore_.Wait();
6915 i::PrintF("iteration %d took %f ms\n", i,
6916 timer.Elapsed().InMillisecondsF());
6917 }
6918
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006919 isolate_->TerminateExecution();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006920 }
6921
6922 void StartSending() { semaphore_.Signal(); }
6923
6924 private:
6925 v8::base::Semaphore semaphore_;
6926 v8::Isolate* isolate_;
6927};
6928
6929
6930static void StartSendingCommands(
6931 const v8::FunctionCallbackInfo<v8::Value>& info) {
6932 send_command_thread_->StartSending();
6933}
6934
6935
6936TEST(ProcessDebugMessagesThreaded) {
6937 DebugLocalContext env;
6938 v8::Isolate* isolate = env->GetIsolate();
6939 v8::HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006940 v8::Local<v8::Context> context = env.context();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006941
6942 counting_message_handler_counter = 0;
6943
6944 v8::Debug::SetMessageHandler(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006945 isolate, SendCommandThread::CountingAndSignallingMessageHandler);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006946 send_command_thread_ = new SendCommandThread(isolate);
6947 send_command_thread_->Start();
6948
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006949 v8::Local<v8::FunctionTemplate> start =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006950 v8::FunctionTemplate::New(isolate, StartSendingCommands);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006951 CHECK(env->Global()
6952 ->Set(context, v8_str("start"),
6953 start->GetFunction(context).ToLocalChecked())
6954 .FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006955
6956 CompileRun("start(); while (true) { }");
6957
6958 CHECK_EQ(20, counting_message_handler_counter);
6959
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006960 v8::Debug::SetMessageHandler(isolate, nullptr);
6961 CheckDebuggerUnloaded(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00006962}
6963
6964
Steve Block6ded16b2010-05-10 14:33:55 +01006965struct BacktraceData {
Leon Clarked91b9f72010-01-27 17:25:45 +00006966 static int frame_counter;
6967 static void MessageHandler(const v8::Debug::Message& message) {
6968 char print_buffer[1000];
6969 v8::String::Value json(message.GetJSON());
6970 Utf16ToAscii(*json, json.length(), print_buffer, 1000);
6971
6972 if (strstr(print_buffer, "backtrace") == NULL) {
6973 return;
6974 }
6975 frame_counter = GetTotalFramesInt(print_buffer);
6976 }
6977};
6978
Steve Block6ded16b2010-05-10 14:33:55 +01006979int BacktraceData::frame_counter;
Leon Clarked91b9f72010-01-27 17:25:45 +00006980
6981
6982// Test that debug messages get processed when ProcessDebugMessages is called.
6983TEST(Backtrace) {
Leon Clarked91b9f72010-01-27 17:25:45 +00006984 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006985 v8::Isolate* isolate = env->GetIsolate();
6986 v8::HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006987 v8::Local<v8::Context> context = env.context();
Leon Clarked91b9f72010-01-27 17:25:45 +00006988
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006989 v8::Debug::SetMessageHandler(isolate, BacktraceData::MessageHandler);
Leon Clarked91b9f72010-01-27 17:25:45 +00006990
6991 const int kBufferSize = 1000;
6992 uint16_t buffer[kBufferSize];
6993 const char* scripts_command =
6994 "{\"seq\":0,"
6995 "\"type\":\"request\","
6996 "\"command\":\"backtrace\"}";
6997
6998 // Check backtrace from ProcessDebugMessages.
Steve Block6ded16b2010-05-10 14:33:55 +01006999 BacktraceData::frame_counter = -10;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007000 v8::Debug::SendCommand(
7001 isolate,
7002 buffer,
7003 AsciiToUtf16(scripts_command, buffer),
7004 NULL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007005 v8::Debug::ProcessDebugMessages(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01007006 CHECK_EQ(BacktraceData::frame_counter, 0);
Leon Clarked91b9f72010-01-27 17:25:45 +00007007
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007008 v8::Local<v8::String> void0 = v8_str(env->GetIsolate(), "void(0)");
7009 v8::Local<v8::Script> script = CompileWithOrigin(void0, void0);
Leon Clarked91b9f72010-01-27 17:25:45 +00007010
7011 // Check backtrace from "void(0)" script.
Steve Block6ded16b2010-05-10 14:33:55 +01007012 BacktraceData::frame_counter = -10;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007013 v8::Debug::SendCommand(
7014 isolate,
7015 buffer,
7016 AsciiToUtf16(scripts_command, buffer),
7017 NULL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007018 script->Run(context).ToLocalChecked();
Steve Block6ded16b2010-05-10 14:33:55 +01007019 CHECK_EQ(BacktraceData::frame_counter, 1);
Leon Clarked91b9f72010-01-27 17:25:45 +00007020
7021 // Get rid of the debug message handler.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007022 v8::Debug::SetMessageHandler(isolate, nullptr);
7023 CheckDebuggerUnloaded(isolate);
Leon Clarked91b9f72010-01-27 17:25:45 +00007024}
7025
7026
Steve Blocka7e24c12009-10-30 11:49:00 +00007027TEST(GetMirror) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007028 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007029 v8::Isolate* isolate = env->GetIsolate();
7030 v8::HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007031 v8::Local<v8::Context> context = env.context();
7032 v8::Local<v8::Value> obj =
7033 v8::Debug::GetMirror(context, v8_str(isolate, "hodja")).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007034 v8::ScriptCompiler::Source source(v8_str(
7035 "function runTest(mirror) {"
7036 " return mirror.isString() && (mirror.length() == 5);"
7037 "}"
7038 ""
7039 "runTest;"));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007040 v8::Local<v8::Function> run_test = v8::Local<v8::Function>::Cast(
7041 v8::ScriptCompiler::CompileUnboundScript(isolate, &source)
7042 .ToLocalChecked()
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007043 ->BindToCurrentContext()
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007044 ->Run(context)
7045 .ToLocalChecked());
7046 v8::Local<v8::Value> result =
7047 run_test->Call(context, env->Global(), 1, &obj).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00007048 CHECK(result->IsTrue());
7049}
Steve Blockd0582a62009-12-15 09:54:21 +00007050
7051
7052// Test that the debug break flag works with function.apply.
7053TEST(DebugBreakFunctionApply) {
Steve Blockd0582a62009-12-15 09:54:21 +00007054 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007055 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007056 v8::Local<v8::Context> context = env.context();
Steve Blockd0582a62009-12-15 09:54:21 +00007057
7058 // Create a function for testing breaking in apply.
7059 v8::Local<v8::Function> foo = CompileFunction(
7060 &env,
7061 "function baz(x) { }"
7062 "function bar(x) { baz(); }"
7063 "function foo(){ bar.apply(this, [1]); }",
7064 "foo");
7065
7066 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007067 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventBreakMax);
Steve Blockd0582a62009-12-15 09:54:21 +00007068
7069 // Set the debug break flag before calling the code using function.apply.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007070 v8::Debug::DebugBreak(env->GetIsolate());
Steve Blockd0582a62009-12-15 09:54:21 +00007071
7072 // Limit the number of debug breaks. This is a regression test for issue 493
7073 // where this test would enter an infinite loop.
7074 break_point_hit_count = 0;
7075 max_break_point_hit_count = 10000; // 10000 => infinite loop.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007076 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00007077
7078 // When keeping the debug break several break will happen.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007079 CHECK_GT(break_point_hit_count, 1);
Steve Blockd0582a62009-12-15 09:54:21 +00007080
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007081 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
7082 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blockd0582a62009-12-15 09:54:21 +00007083}
7084
7085
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007086v8::Local<v8::Context> debugee_context;
7087v8::Local<v8::Context> debugger_context;
Steve Blockd0582a62009-12-15 09:54:21 +00007088
7089
7090// Property getter that checks that current and calling contexts
7091// are both the debugee contexts.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007092static void NamedGetterWithCallingContextCheck(
Steve Blockd0582a62009-12-15 09:54:21 +00007093 v8::Local<v8::String> name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007094 const v8::PropertyCallbackInfo<v8::Value>& info) {
7095 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(name), "a"));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007096 v8::Local<v8::Context> current = info.GetIsolate()->GetCurrentContext();
Steve Blockd0582a62009-12-15 09:54:21 +00007097 CHECK(current == debugee_context);
7098 CHECK(current != debugger_context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007099 info.GetReturnValue().Set(1);
Steve Blockd0582a62009-12-15 09:54:21 +00007100}
7101
7102
7103// Debug event listener that checks if the first argument of a function is
7104// an object with property 'a' == 1. If the property has custom accessor
7105// this handler will eventually invoke it.
7106static void DebugEventGetAtgumentPropertyValue(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007107 const v8::Debug::EventDetails& event_details) {
7108 v8::DebugEvent event = event_details.GetEvent();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007109 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
Steve Blockd0582a62009-12-15 09:54:21 +00007110 if (event == v8::Break) {
7111 break_point_hit_count++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007112 CHECK(debugger_context == CcTest::isolate()->GetCurrentContext());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007113 v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(CompileRun(
Steve Blockd0582a62009-12-15 09:54:21 +00007114 "(function(exec_state) {\n"
7115 " return (exec_state.frame(0).argumentValue(0).property('a').\n"
7116 " value().value() == 1);\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007117 "})"));
Steve Blockd0582a62009-12-15 09:54:21 +00007118 const int argc = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007119 v8::Local<v8::Value> argv[argc] = {exec_state};
7120 v8::Local<v8::Value> result =
7121 func->Call(debugger_context, exec_state, argc, argv).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00007122 CHECK(result->IsTrue());
7123 }
7124}
7125
7126
7127TEST(CallingContextIsNotDebugContext) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007128 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
Steve Blockd0582a62009-12-15 09:54:21 +00007129 // Create and enter a debugee context.
Steve Blockd0582a62009-12-15 09:54:21 +00007130 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007131 v8::Isolate* isolate = env->GetIsolate();
7132 v8::HandleScope scope(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +00007133 env.ExposeDebug();
7134
7135 // Save handles to the debugger and debugee contexts to be used in
7136 // NamedGetterWithCallingContextCheck.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007137 debugee_context = env.context();
Steve Block44f0eee2011-05-26 01:26:41 +01007138 debugger_context = v8::Utils::ToLocal(debug->debug_context());
Steve Blockd0582a62009-12-15 09:54:21 +00007139
7140 // Create object with 'a' property accessor.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007141 v8::Local<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
7142 named->SetAccessor(v8_str(isolate, "a"), NamedGetterWithCallingContextCheck);
7143 CHECK(env->Global()
7144 ->Set(debugee_context, v8_str(isolate, "obj"),
7145 named->NewInstance(debugee_context).ToLocalChecked())
7146 .FromJust());
Steve Blockd0582a62009-12-15 09:54:21 +00007147
7148 // Register the debug event listener
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007149 v8::Debug::SetDebugEventListener(isolate, DebugEventGetAtgumentPropertyValue);
Steve Blockd0582a62009-12-15 09:54:21 +00007150
7151 // Create a function that invokes debugger.
7152 v8::Local<v8::Function> foo = CompileFunction(
7153 &env,
7154 "function bar(x) { debugger; }"
7155 "function foo(){ bar(obj); }",
7156 "foo");
7157
7158 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007159 foo->Call(debugee_context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00007160 CHECK_EQ(1, break_point_hit_count);
7161
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007162 v8::Debug::SetDebugEventListener(isolate, nullptr);
7163 debugee_context = v8::Local<v8::Context>();
7164 debugger_context = v8::Local<v8::Context>();
7165 CheckDebuggerUnloaded(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +00007166}
Steve Block6ded16b2010-05-10 14:33:55 +01007167
7168
7169TEST(DebugContextIsPreservedBetweenAccesses) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007170 v8::HandleScope scope(CcTest::isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007171 v8::Debug::SetDebugEventListener(CcTest::isolate(),
7172 DebugEventBreakPointHitCount);
7173 v8::Local<v8::Context> context1 =
7174 v8::Debug::GetDebugContext(CcTest::isolate());
7175 v8::Local<v8::Context> context2 =
7176 v8::Debug::GetDebugContext(CcTest::isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007177 CHECK(v8::Utils::OpenHandle(*context1).is_identical_to(
7178 v8::Utils::OpenHandle(*context2)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007179 v8::Debug::SetDebugEventListener(CcTest::isolate(), nullptr);
Leon Clarkef7060e22010-06-03 12:02:55 +01007180}
7181
7182
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007183TEST(NoDebugContextWhenDebuggerDisabled) {
7184 v8::HandleScope scope(CcTest::isolate());
7185 v8::Local<v8::Context> context =
7186 v8::Debug::GetDebugContext(CcTest::isolate());
7187 CHECK(context.IsEmpty());
7188}
7189
7190
7191static v8::Local<v8::Value> expected_callback_data;
Leon Clarkef7060e22010-06-03 12:02:55 +01007192static void DebugEventContextChecker(const v8::Debug::EventDetails& details) {
7193 CHECK(details.GetEventContext() == expected_context);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007194 CHECK(expected_callback_data->Equals(details.GetEventContext(),
7195 details.GetCallbackData())
7196 .FromJust());
Leon Clarkef7060e22010-06-03 12:02:55 +01007197}
7198
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007199
Leon Clarkef7060e22010-06-03 12:02:55 +01007200// Check that event details contain context where debug event occured.
7201TEST(DebugEventContext) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007202 v8::Isolate* isolate = CcTest::isolate();
7203 v8::HandleScope scope(isolate);
7204 expected_context = v8::Context::New(isolate);
7205 expected_callback_data = v8::Int32::New(isolate, 2010);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007206 v8::Debug::SetDebugEventListener(isolate, DebugEventContextChecker,
7207 expected_callback_data);
Leon Clarkef7060e22010-06-03 12:02:55 +01007208 v8::Context::Scope context_scope(expected_context);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007209 v8::Script::Compile(expected_context,
7210 v8_str(isolate, "(function(){debugger;})();"))
7211 .ToLocalChecked()
7212 ->Run(expected_context)
7213 .ToLocalChecked();
Leon Clarkef7060e22010-06-03 12:02:55 +01007214 expected_context.Clear();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007215 v8::Debug::SetDebugEventListener(isolate, nullptr);
7216 expected_context_data = v8::Local<v8::Value>();
7217 CheckDebuggerUnloaded(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01007218}
Leon Clarkef7060e22010-06-03 12:02:55 +01007219
Ben Murdoch3bec4d22010-07-22 14:51:16 +01007220
Ben Murdochb0fe1622011-05-05 13:52:32 +01007221static bool debug_event_break_deoptimize_done = false;
7222
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007223static void DebugEventBreakDeoptimize(
7224 const v8::Debug::EventDetails& event_details) {
7225 v8::DebugEvent event = event_details.GetEvent();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007226 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
7227 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007228 if (event == v8::Break) {
7229 if (!frame_function_name.IsEmpty()) {
7230 // Get the name of the function.
7231 const int argc = 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007232 v8::Local<v8::Value> argv[argc] = {
7233 exec_state, v8::Integer::New(CcTest::isolate(), 0)};
7234 v8::Local<v8::Value> result =
7235 frame_function_name->Call(context, exec_state, argc, argv)
7236 .ToLocalChecked();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007237 if (!result->IsUndefined()) {
7238 char fn[80];
7239 CHECK(result->IsString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007240 v8::Local<v8::String> function_name(
7241 result->ToString(context).ToLocalChecked());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007242 function_name->WriteUtf8(fn);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007243 if (strcmp(fn, "bar") == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007244 i::Deoptimizer::DeoptimizeAll(CcTest::i_isolate());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007245 debug_event_break_deoptimize_done = true;
7246 }
7247 }
7248 }
7249
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007250 v8::Debug::DebugBreak(CcTest::isolate());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007251 }
7252}
7253
7254
7255// Test deoptimization when execution is broken using the debug break stack
7256// check interrupt.
7257TEST(DeoptimizeDuringDebugBreak) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007258 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007259 v8::HandleScope scope(env->GetIsolate());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007260 env.ExposeDebug();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007261 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007262
7263 // Create a function for checking the function when hitting a break point.
7264 frame_function_name = CompileFunction(&env,
7265 frame_function_name_source,
7266 "frame_function_name");
7267
Ben Murdochb0fe1622011-05-05 13:52:32 +01007268 // Set a debug event listener which will keep interrupting execution until
7269 // debug break. When inside function bar it will deoptimize all functions.
7270 // This tests lazy deoptimization bailout for the stack check, as the first
7271 // time in function bar when using debug break and no break points will be at
7272 // the initial stack check.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007273 v8::Debug::SetDebugEventListener(env->GetIsolate(),
7274 DebugEventBreakDeoptimize);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007275
7276 // Compile and run function bar which will optimize it for some flag settings.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007277 v8::Local<v8::Function> f = CompileFunction(&env, "function bar(){}", "bar");
7278 f->Call(context, v8::Undefined(env->GetIsolate()), 0, NULL).ToLocalChecked();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007279
7280 // Set debug break and call bar again.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007281 v8::Debug::DebugBreak(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007282 f->Call(context, v8::Undefined(env->GetIsolate()), 0, NULL).ToLocalChecked();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007283
7284 CHECK(debug_event_break_deoptimize_done);
7285
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007286 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007287}
7288
7289
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007290static void DebugEventBreakWithOptimizedStack(
7291 const v8::Debug::EventDetails& event_details) {
7292 v8::Isolate* isolate = event_details.GetEventContext()->GetIsolate();
7293 v8::DebugEvent event = event_details.GetEvent();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007294 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
7295 v8::Local<v8::Context> context = isolate->GetCurrentContext();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007296 if (event == v8::Break) {
7297 if (!frame_function_name.IsEmpty()) {
7298 for (int i = 0; i < 2; i++) {
7299 const int argc = 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007300 v8::Local<v8::Value> argv[argc] = {exec_state,
7301 v8::Integer::New(isolate, i)};
Ben Murdochb0fe1622011-05-05 13:52:32 +01007302 // Get the name of the function in frame i.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007303 v8::Local<v8::Value> result =
7304 frame_function_name->Call(context, exec_state, argc, argv)
7305 .ToLocalChecked();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007306 CHECK(result->IsString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007307 v8::Local<v8::String> function_name(
7308 result->ToString(context).ToLocalChecked());
7309 CHECK(
7310 function_name->Equals(context, v8_str(isolate, "loop")).FromJust());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007311 // Get the name of the first argument in frame i.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007312 result = frame_argument_name->Call(context, exec_state, argc, argv)
7313 .ToLocalChecked();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007314 CHECK(result->IsString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007315 v8::Local<v8::String> argument_name(
7316 result->ToString(context).ToLocalChecked());
7317 CHECK(argument_name->Equals(context, v8_str(isolate, "count"))
7318 .FromJust());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007319 // Get the value of the first argument in frame i. If the
Ben Murdoch097c5b22016-05-18 11:27:45 +01007320 // function is optimized the value will be undefined, otherwise
Ben Murdochb0fe1622011-05-05 13:52:32 +01007321 // the value will be '1 - i'.
7322 //
7323 // TODO(3141533): We should be able to get the real value for
7324 // optimized frames.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007325 result = frame_argument_value->Call(context, exec_state, argc, argv)
7326 .ToLocalChecked();
7327 CHECK(result->IsUndefined() ||
7328 (result->Int32Value(context).FromJust() == 1 - i));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007329 // Get the name of the first local variable.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007330 result = frame_local_name->Call(context, exec_state, argc, argv)
7331 .ToLocalChecked();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007332 CHECK(result->IsString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007333 v8::Local<v8::String> local_name(
7334 result->ToString(context).ToLocalChecked());
7335 CHECK(local_name->Equals(context, v8_str(isolate, "local")).FromJust());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007336 // Get the value of the first local variable. If the function
7337 // is optimized the value will be undefined, otherwise it will
7338 // be 42.
7339 //
7340 // TODO(3141533): We should be able to get the real value for
7341 // optimized frames.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007342 result = frame_local_value->Call(context, exec_state, argc, argv)
7343 .ToLocalChecked();
7344 CHECK(result->IsUndefined() ||
7345 (result->Int32Value(context).FromJust() == 42));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007346 }
7347 }
7348 }
7349}
7350
7351
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007352static void ScheduleBreak(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007353 v8::Debug::SetDebugEventListener(args.GetIsolate(),
7354 DebugEventBreakWithOptimizedStack);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007355 v8::Debug::DebugBreak(args.GetIsolate());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007356}
7357
7358
7359TEST(DebugBreakStackInspection) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007360 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007361 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007362 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007363
7364 frame_function_name =
7365 CompileFunction(&env, frame_function_name_source, "frame_function_name");
7366 frame_argument_name =
7367 CompileFunction(&env, frame_argument_name_source, "frame_argument_name");
7368 frame_argument_value = CompileFunction(&env,
7369 frame_argument_value_source,
7370 "frame_argument_value");
7371 frame_local_name =
7372 CompileFunction(&env, frame_local_name_source, "frame_local_name");
7373 frame_local_value =
7374 CompileFunction(&env, frame_local_value_source, "frame_local_value");
7375
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007376 v8::Local<v8::FunctionTemplate> schedule_break_template =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007377 v8::FunctionTemplate::New(env->GetIsolate(), ScheduleBreak);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007378 v8::Local<v8::Function> schedule_break =
7379 schedule_break_template->GetFunction(context).ToLocalChecked();
7380 CHECK(env->Global()
7381 ->Set(context, v8_str("scheduleBreak"), schedule_break)
7382 .FromJust());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007383
7384 const char* src =
7385 "function loop(count) {"
7386 " var local = 42;"
7387 " if (count < 1) { scheduleBreak(); loop(count + 1); }"
7388 "}"
7389 "loop(0);";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007390 v8::Script::Compile(context, v8_str(env->GetIsolate(), src))
7391 .ToLocalChecked()
7392 ->Run(context)
7393 .ToLocalChecked();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007394}
7395
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007396
7397// Test that setting the terminate execution flag during debug break processing.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007398static void TestDebugBreakInLoop(const char* loop_head,
7399 const char** loop_bodies,
7400 const char* loop_tail) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007401 // Receive 10 breaks for each test and then terminate JavaScript execution.
7402 static const int kBreaksPerTest = 10;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007403
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007404 for (int i = 0; loop_bodies[i] != NULL; i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007405 // Perform a lazy deoptimization after various numbers of breaks
7406 // have been hit.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007407
7408 EmbeddedVector<char, 1024> buffer;
7409 SNPrintF(buffer, "function f() {%s%s%s}", loop_head, loop_bodies[i],
7410 loop_tail);
7411
7412 i::PrintF("%s\n", buffer.start());
7413
7414 for (int j = 0; j < 3; j++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007415 break_point_hit_count_deoptimize = j;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007416 if (j == 2) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007417 break_point_hit_count_deoptimize = kBreaksPerTest;
7418 }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007419
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007420 break_point_hit_count = 0;
7421 max_break_point_hit_count = kBreaksPerTest;
7422 terminate_after_max_break_point_hit = true;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007423
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007424 // Function with infinite loop.
7425 CompileRun(buffer.start());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007426
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007427 // Set the debug break to enter the debugger as soon as possible.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007428 v8::Debug::DebugBreak(CcTest::isolate());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007429
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007430 // Call function with infinite loop.
7431 CompileRun("f();");
7432 CHECK_EQ(kBreaksPerTest, break_point_hit_count);
7433
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007434 CHECK(!CcTest::isolate()->IsExecutionTerminating());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007435 }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007436 }
7437}
7438
7439
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007440static const char* loop_bodies_1[] = {"",
7441 "g()",
7442 "if (a == 0) { g() }",
7443 "if (a == 1) { g() }",
7444 "if (a == 0) { g() } else { h() }",
7445 "if (a == 0) { continue }",
7446 NULL};
7447
7448
7449static const char* loop_bodies_2[] = {
7450 "if (a == 1) { continue }",
7451 "switch (a) { case 1: g(); }",
7452 "switch (a) { case 1: continue; }",
7453 "switch (a) { case 1: g(); break; default: h() }",
7454 "switch (a) { case 1: continue; break; default: h() }",
7455 NULL};
7456
7457
7458void DebugBreakLoop(const char* loop_header, const char** loop_bodies,
7459 const char* loop_footer) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007460 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007461 v8::HandleScope scope(env->GetIsolate());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007462
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007463 // Register a debug event listener which sets the break flag and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007464 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventBreakMax);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007465
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007466 CompileRun(
7467 "var a = 1;\n"
7468 "function g() { }\n"
7469 "function h() { }");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007470
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007471 TestDebugBreakInLoop(loop_header, loop_bodies, loop_footer);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007472
7473 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007474 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
7475 CheckDebuggerUnloaded(env->GetIsolate());
7476}
7477
7478
7479TEST(DebugBreakInWhileTrue1) {
7480 DebugBreakLoop("while (true) {", loop_bodies_1, "}");
7481}
7482
7483
7484TEST(DebugBreakInWhileTrue2) {
7485 DebugBreakLoop("while (true) {", loop_bodies_2, "}");
7486}
7487
7488
7489TEST(DebugBreakInWhileCondition1) {
7490 DebugBreakLoop("while (a == 1) {", loop_bodies_1, "}");
7491}
7492
7493
7494TEST(DebugBreakInWhileCondition2) {
7495 DebugBreakLoop("while (a == 1) {", loop_bodies_2, "}");
7496}
7497
7498
7499TEST(DebugBreakInDoWhileTrue1) {
7500 DebugBreakLoop("do {", loop_bodies_1, "} while (true)");
7501}
7502
7503
7504TEST(DebugBreakInDoWhileTrue2) {
7505 DebugBreakLoop("do {", loop_bodies_2, "} while (true)");
7506}
7507
7508
7509TEST(DebugBreakInDoWhileCondition1) {
7510 DebugBreakLoop("do {", loop_bodies_1, "} while (a == 1)");
7511}
7512
7513
7514TEST(DebugBreakInDoWhileCondition2) {
7515 DebugBreakLoop("do {", loop_bodies_2, "} while (a == 1)");
7516}
7517
7518
7519TEST(DebugBreakInFor1) { DebugBreakLoop("for (;;) {", loop_bodies_1, "}"); }
7520
7521
7522TEST(DebugBreakInFor2) { DebugBreakLoop("for (;;) {", loop_bodies_2, "}"); }
7523
7524
7525TEST(DebugBreakInForCondition1) {
7526 DebugBreakLoop("for (;a == 1;) {", loop_bodies_1, "}");
7527}
7528
7529
7530TEST(DebugBreakInForCondition2) {
7531 DebugBreakLoop("for (;a == 1;) {", loop_bodies_2, "}");
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007532}
7533
7534
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007535v8::Local<v8::Script> inline_script;
7536
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007537static void DebugBreakInlineListener(
7538 const v8::Debug::EventDetails& event_details) {
7539 v8::DebugEvent event = event_details.GetEvent();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007540 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007541 if (event != v8::Break) return;
7542
7543 int expected_frame_count = 4;
7544 int expected_line_number[] = {1, 4, 7, 12};
7545
7546 i::Handle<i::Object> compiled_script = v8::Utils::OpenHandle(*inline_script);
7547 i::Handle<i::Script> source_script = i::Handle<i::Script>(i::Script::cast(
7548 i::JSFunction::cast(*compiled_script)->shared()->script()));
7549
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007550 int break_id = CcTest::i_isolate()->debug()->break_id();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007551 char script[128];
7552 i::Vector<char> script_vector(script, sizeof(script));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007553 SNPrintF(script_vector, "%%GetFrameCount(%d)", break_id);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007554 v8::Local<v8::Value> result = CompileRun(script);
7555
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007556 int frame_count = result->Int32Value(context).FromJust();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007557 CHECK_EQ(expected_frame_count, frame_count);
7558
7559 for (int i = 0; i < frame_count; i++) {
7560 // The 5. element in the returned array of GetFrameDetails contains the
7561 // source position of that frame.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007562 SNPrintF(script_vector, "%%GetFrameDetails(%d, %d)[5]", break_id, i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007563 v8::Local<v8::Value> result = CompileRun(script);
7564 CHECK_EQ(expected_line_number[i],
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007565 i::Script::GetLineNumber(source_script,
7566 result->Int32Value(context).FromJust()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007567 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007568 v8::Debug::SetDebugEventListener(CcTest::isolate(), nullptr);
7569 CcTest::isolate()->TerminateExecution();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007570}
7571
7572
7573TEST(DebugBreakInline) {
7574 i::FLAG_allow_natives_syntax = true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007575 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007576 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007577 v8::Local<v8::Context> context = env.context();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007578 const char* source =
7579 "function debug(b) { \n"
7580 " if (b) debugger; \n"
7581 "} \n"
7582 "function f(b) { \n"
7583 " debug(b) \n"
7584 "}; \n"
7585 "function g(b) { \n"
7586 " f(b); \n"
7587 "}; \n"
7588 "g(false); \n"
7589 "g(false); \n"
7590 "%OptimizeFunctionOnNextCall(g); \n"
7591 "g(true);";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007592 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugBreakInlineListener);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007593 inline_script =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007594 v8::Script::Compile(context, v8_str(env->GetIsolate(), source))
7595 .ToLocalChecked();
7596 inline_script->Run(context).ToLocalChecked();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007597}
7598
7599
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007600static void DebugEventStepNext(
7601 const v8::Debug::EventDetails& event_details) {
7602 v8::DebugEvent event = event_details.GetEvent();
7603 if (event == v8::Break) {
7604 PrepareStep(StepNext);
7605 }
7606}
7607
7608
7609static void RunScriptInANewCFrame(const char* source) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007610 v8::TryCatch try_catch(CcTest::isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007611 CompileRun(source);
7612 CHECK(try_catch.HasCaught());
7613}
7614
7615
7616TEST(Regress131642) {
7617 // Bug description:
7618 // When doing StepNext through the first script, the debugger is not reset
7619 // after exiting through exception. A flawed implementation enabling the
7620 // debugger to step into Array.prototype.forEach breaks inside the callback
7621 // for forEach in the second script under the assumption that we are in a
7622 // recursive call. In an attempt to step out, we crawl the stack using the
7623 // recorded frame pointer from the first script and fail when not finding it
7624 // on the stack.
7625 DebugLocalContext env;
7626 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007627 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStepNext);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007628
7629 // We step through the first script. It exits through an exception. We run
7630 // this inside a new frame to record a different FP than the second script
7631 // would expect.
7632 const char* script_1 = "debugger; throw new Error();";
7633 RunScriptInANewCFrame(script_1);
7634
7635 // The second script uses forEach.
7636 const char* script_2 = "[0].forEach(function() { });";
7637 CompileRun(script_2);
7638
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007639 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007640}
7641
7642
7643// Import from test-heap.cc
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007644namespace v8 {
7645namespace internal {
7646
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007647int CountNativeContexts();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007648}
7649}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007650
7651
7652static void NopListener(const v8::Debug::EventDetails& event_details) {
7653}
7654
7655
7656TEST(DebuggerCreatesContextIffActive) {
7657 DebugLocalContext env;
7658 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007659 CHECK_EQ(1, v8::internal::CountNativeContexts());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007660
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007661 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007662 CompileRun("debugger;");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007663 CHECK_EQ(1, v8::internal::CountNativeContexts());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007664
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007665 v8::Debug::SetDebugEventListener(env->GetIsolate(), NopListener);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007666 CompileRun("debugger;");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007667 CHECK_EQ(2, v8::internal::CountNativeContexts());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007668
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007669 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007670}
7671
7672
7673TEST(LiveEditEnabled) {
7674 v8::internal::FLAG_allow_natives_syntax = true;
7675 LocalContext env;
7676 v8::HandleScope scope(env->GetIsolate());
7677 v8::Debug::SetLiveEditEnabled(env->GetIsolate(), true);
7678 CompileRun("%LiveEditCompareStrings('', '')");
7679}
7680
7681
7682TEST(LiveEditDisabled) {
7683 v8::internal::FLAG_allow_natives_syntax = true;
7684 LocalContext env;
7685 v8::HandleScope scope(env->GetIsolate());
7686 v8::Debug::SetLiveEditEnabled(env->GetIsolate(), false);
7687 CompileRun("%LiveEditCompareStrings('', '')");
7688}
7689
7690
7691TEST(PrecompiledFunction) {
7692 // Regression test for crbug.com/346207. If we have preparse data, parsing the
7693 // function in the presence of the debugger (and breakpoints) should still
7694 // succeed. The bug was that preparsing was done lazily and parsing was done
7695 // eagerly, so, the symbol streams didn't match.
7696 DebugLocalContext env;
7697 v8::HandleScope scope(env->GetIsolate());
7698 env.ExposeDebug();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007699 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugBreakInlineListener);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007700
7701 v8::Local<v8::Function> break_here =
7702 CompileFunction(&env, "function break_here(){}", "break_here");
7703 SetBreakPoint(break_here, 0);
7704
7705 const char* source =
7706 "var a = b = c = 1; \n"
7707 "function this_is_lazy() { \n"
7708 // This symbol won't appear in the preparse data.
7709 " var a; \n"
7710 "} \n"
7711 "function bar() { \n"
7712 " return \"bar\"; \n"
7713 "}; \n"
7714 "a = b = c = 2; \n"
7715 "bar(); \n";
7716 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
7717 CHECK(result->IsString());
7718 v8::String::Utf8Value utf8(result);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007719 CHECK_EQ(0, strcmp("bar", *utf8));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007720
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007721 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
7722 CheckDebuggerUnloaded(env->GetIsolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007723}
7724
7725
7726static void DebugBreakStackTraceListener(
7727 const v8::Debug::EventDetails& event_details) {
7728 v8::StackTrace::CurrentStackTrace(CcTest::isolate(), 10);
7729}
7730
7731
7732static void AddDebugBreak(const v8::FunctionCallbackInfo<v8::Value>& args) {
7733 v8::Debug::DebugBreak(args.GetIsolate());
7734}
7735
7736
7737TEST(DebugBreakStackTrace) {
7738 DebugLocalContext env;
7739 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007740 v8::Debug::SetDebugEventListener(env->GetIsolate(),
7741 DebugBreakStackTraceListener);
7742 v8::Local<v8::Context> context = env.context();
7743 v8::Local<v8::FunctionTemplate> add_debug_break_template =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007744 v8::FunctionTemplate::New(env->GetIsolate(), AddDebugBreak);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007745 v8::Local<v8::Function> add_debug_break =
7746 add_debug_break_template->GetFunction(context).ToLocalChecked();
7747 CHECK(env->Global()
7748 ->Set(context, v8_str("add_debug_break"), add_debug_break)
7749 .FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007750
7751 CompileRun("(function loop() {"
7752 " for (var j = 0; j < 1000; j++) {"
7753 " for (var i = 0; i < 1000; i++) {"
7754 " if (i == 999) add_debug_break();"
7755 " }"
7756 " }"
7757 "})()");
7758}
7759
7760
7761v8::base::Semaphore terminate_requested_semaphore(0);
7762v8::base::Semaphore terminate_fired_semaphore(0);
7763bool terminate_already_fired = false;
7764
7765
7766static void DebugBreakTriggerTerminate(
7767 const v8::Debug::EventDetails& event_details) {
7768 if (event_details.GetEvent() != v8::Break || terminate_already_fired) return;
7769 terminate_requested_semaphore.Signal();
7770 // Wait for at most 2 seconds for the terminate request.
7771 CHECK(terminate_fired_semaphore.WaitFor(v8::base::TimeDelta::FromSeconds(2)));
7772 terminate_already_fired = true;
7773}
7774
7775
7776class TerminationThread : public v8::base::Thread {
7777 public:
7778 explicit TerminationThread(v8::Isolate* isolate)
7779 : Thread(Options("terminator")), isolate_(isolate) {}
7780
7781 virtual void Run() {
7782 terminate_requested_semaphore.Wait();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007783 isolate_->TerminateExecution();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007784 terminate_fired_semaphore.Signal();
7785 }
7786
7787 private:
7788 v8::Isolate* isolate_;
7789};
7790
7791
7792TEST(DebugBreakOffThreadTerminate) {
7793 DebugLocalContext env;
7794 v8::Isolate* isolate = env->GetIsolate();
7795 v8::HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007796 v8::Debug::SetDebugEventListener(isolate, DebugBreakTriggerTerminate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007797 TerminationThread terminator(isolate);
7798 terminator.Start();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007799 v8::TryCatch try_catch(env->GetIsolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007800 v8::Debug::DebugBreak(isolate);
7801 CompileRun("while (true);");
7802 CHECK(try_catch.HasTerminated());
7803}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007804
7805
7806static void DebugEventExpectNoException(
7807 const v8::Debug::EventDetails& event_details) {
7808 v8::DebugEvent event = event_details.GetEvent();
7809 CHECK_NE(v8::Exception, event);
7810}
7811
7812
7813static void TryCatchWrappedThrowCallback(
7814 const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007815 v8::TryCatch try_catch(args.GetIsolate());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007816 CompileRun("throw 'rejection';");
7817 CHECK(try_catch.HasCaught());
7818}
7819
7820
7821TEST(DebugPromiseInterceptedByTryCatch) {
7822 DebugLocalContext env;
7823 v8::Isolate* isolate = env->GetIsolate();
7824 v8::HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007825 v8::Debug::SetDebugEventListener(isolate, &DebugEventExpectNoException);
7826 v8::Local<v8::Context> context = env.context();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007827 ChangeBreakOnException(false, true);
7828
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007829 v8::Local<v8::FunctionTemplate> fun =
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007830 v8::FunctionTemplate::New(isolate, TryCatchWrappedThrowCallback);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007831 CHECK(env->Global()
7832 ->Set(context, v8_str("fun"),
7833 fun->GetFunction(context).ToLocalChecked())
7834 .FromJust());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007835
7836 CompileRun("var p = new Promise(function(res, rej) { fun(); res(); });");
7837 CompileRun(
7838 "var r;"
7839 "p.chain(function() { r = 'resolved'; },"
7840 " function() { r = 'rejected'; });");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007841 CHECK(CompileRun("r")->Equals(context, v8_str("resolved")).FromJust());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007842}
7843
7844
7845static int exception_event_counter = 0;
7846
7847
7848static void DebugEventCountException(
7849 const v8::Debug::EventDetails& event_details) {
7850 v8::DebugEvent event = event_details.GetEvent();
7851 if (event == v8::Exception) exception_event_counter++;
7852}
7853
7854
7855static void ThrowCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
7856 CompileRun("throw 'rejection';");
7857}
7858
7859
7860TEST(DebugPromiseRejectedByCallback) {
7861 DebugLocalContext env;
7862 v8::Isolate* isolate = env->GetIsolate();
7863 v8::HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007864 v8::Debug::SetDebugEventListener(isolate, &DebugEventCountException);
7865 v8::Local<v8::Context> context = env.context();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007866 ChangeBreakOnException(false, true);
7867 exception_event_counter = 0;
7868
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007869 v8::Local<v8::FunctionTemplate> fun =
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007870 v8::FunctionTemplate::New(isolate, ThrowCallback);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007871 CHECK(env->Global()
7872 ->Set(context, v8_str("fun"),
7873 fun->GetFunction(context).ToLocalChecked())
7874 .FromJust());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007875
7876 CompileRun("var p = new Promise(function(res, rej) { fun(); res(); });");
7877 CompileRun(
7878 "var r;"
7879 "p.chain(function() { r = 'resolved'; },"
7880 " function(e) { r = 'rejected' + e; });");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007881 CHECK(
7882 CompileRun("r")->Equals(context, v8_str("rejectedrejection")).FromJust());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007883 CHECK_EQ(1, exception_event_counter);
7884}
7885
7886
7887TEST(DebugBreakOnExceptionInObserveCallback) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007888 i::FLAG_harmony_object_observe = true;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007889 DebugLocalContext env;
7890 v8::Isolate* isolate = env->GetIsolate();
7891 v8::HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007892 v8::Debug::SetDebugEventListener(isolate, &DebugEventCountException);
7893 v8::Local<v8::Context> context = env.context();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007894 // Break on uncaught exception
7895 ChangeBreakOnException(false, true);
7896 exception_event_counter = 0;
7897
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007898 v8::Local<v8::FunctionTemplate> fun =
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007899 v8::FunctionTemplate::New(isolate, ThrowCallback);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007900 CHECK(env->Global()
7901 ->Set(context, v8_str("fun"),
7902 fun->GetFunction(context).ToLocalChecked())
7903 .FromJust());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007904
7905 CompileRun(
7906 "var obj = {};"
7907 "var callbackRan = false;"
7908 "Object.observe(obj, function() {"
7909 " callbackRan = true;"
7910 " throw Error('foo');"
7911 "});"
7912 "obj.prop = 1");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007913 CHECK(CompileRun("callbackRan")->BooleanValue(context).FromJust());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007914 CHECK_EQ(1, exception_event_counter);
7915}
7916
7917
7918static void DebugHarmonyScopingListener(
7919 const v8::Debug::EventDetails& event_details) {
7920 v8::DebugEvent event = event_details.GetEvent();
7921 if (event != v8::Break) return;
7922
7923 int break_id = CcTest::i_isolate()->debug()->break_id();
7924
7925 char script[128];
7926 i::Vector<char> script_vector(script, sizeof(script));
7927 SNPrintF(script_vector, "%%GetFrameCount(%d)", break_id);
7928 ExpectInt32(script, 1);
7929
7930 SNPrintF(script_vector, "var frame = new FrameMirror(%d, 0);", break_id);
7931 CompileRun(script);
7932 ExpectInt32("frame.evaluate('x').value_", 1);
7933 ExpectInt32("frame.evaluate('y').value_", 2);
7934
7935 CompileRun("var allScopes = frame.allScopes()");
7936 ExpectInt32("allScopes.length", 2);
7937
7938 ExpectBoolean("allScopes[0].scopeType() === ScopeType.Script", true);
7939
7940 ExpectInt32("allScopes[0].scopeObject().value_.x", 1);
7941
7942 ExpectInt32("allScopes[0].scopeObject().value_.y", 2);
7943
7944 CompileRun("allScopes[0].setVariableValue('x', 5);");
7945 CompileRun("allScopes[0].setVariableValue('y', 6);");
7946 ExpectInt32("frame.evaluate('x + y').value_", 11);
7947}
7948
7949
7950TEST(DebugBreakInLexicalScopes) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007951 i::FLAG_allow_natives_syntax = true;
7952
7953 DebugLocalContext env;
7954 v8::Isolate* isolate = env->GetIsolate();
7955 v8::HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007956 v8::Debug::SetDebugEventListener(isolate, DebugHarmonyScopingListener);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007957
7958 CompileRun(
7959 "'use strict'; \n"
7960 "let x = 1; \n");
7961 ExpectInt32(
7962 "'use strict'; \n"
7963 "let y = 2; \n"
7964 "debugger; \n"
7965 "x * y",
7966 30);
7967 ExpectInt32(
7968 "x = 1; y = 2; \n"
7969 "debugger;"
7970 "x * y",
7971 30);
7972}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007973
7974static int after_compile_handler_depth = 0;
7975static void HandleInterrupt(v8::Isolate* isolate, void* data) {
7976 CHECK_EQ(0, after_compile_handler_depth);
7977}
7978
7979static void NoInterruptsOnDebugEvent(
7980 const v8::Debug::EventDetails& event_details) {
7981 if (event_details.GetEvent() != v8::AfterCompile) return;
7982 ++after_compile_handler_depth;
7983 // Do not allow nested AfterCompile events.
7984 CHECK(after_compile_handler_depth <= 1);
7985 v8::Isolate* isolate = event_details.GetEventContext()->GetIsolate();
7986 isolate->RequestInterrupt(&HandleInterrupt, nullptr);
7987 CompileRun("function foo() {}; foo();");
7988 --after_compile_handler_depth;
7989}
7990
7991
7992TEST(NoInterruptsInDebugListener) {
7993 DebugLocalContext env;
7994 v8::Debug::SetDebugEventListener(env->GetIsolate(), NoInterruptsOnDebugEvent);
7995 CompileRun("void(0);");
7996}
Ben Murdoch097c5b22016-05-18 11:27:45 +01007997
7998class TestBreakLocation : public i::BreakLocation {
7999 public:
8000 using i::BreakLocation::GetIterator;
8001 using i::BreakLocation::Iterator;
8002};
8003
8004TEST(BreakLocationIterator) {
8005 DebugLocalContext env;
8006 v8::Isolate* isolate = env->GetIsolate();
8007 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
8008 v8::HandleScope scope(isolate);
8009
8010 v8::Local<v8::Value> result = CompileRun(
8011 "function f() {\n"
8012 " debugger; \n"
8013 " f(); \n"
8014 " debugger; \n"
8015 "} \n"
8016 "f");
8017 Handle<i::Object> function_obj = v8::Utils::OpenHandle(*result);
8018 Handle<i::JSFunction> function = Handle<i::JSFunction>::cast(function_obj);
8019 Handle<i::SharedFunctionInfo> shared(function->shared());
8020
8021 EnableDebugger(isolate);
8022 CHECK(i_isolate->debug()->EnsureDebugInfo(shared, function));
8023
8024 Handle<i::DebugInfo> debug_info(shared->GetDebugInfo());
8025 int code_size = debug_info->abstract_code()->Size();
8026
8027 bool found_return = false;
8028 bool found_call = false;
8029 bool found_debugger = false;
8030
8031 // Test public interface.
8032 for (int i = 0; i < code_size; i++) {
8033 i::BreakLocation location = i::BreakLocation::FromCodeOffset(debug_info, i);
8034 if (location.IsCall()) found_call = true;
8035 if (location.IsReturn()) found_return = true;
8036 if (location.IsDebuggerStatement()) found_debugger = true;
8037 }
8038 CHECK(found_call);
8039 CHECK(found_return);
8040 CHECK(found_debugger);
8041
8042 // Test underlying implementation.
8043 TestBreakLocation::Iterator* iterator =
8044 TestBreakLocation::GetIterator(debug_info, i::ALL_BREAK_LOCATIONS);
8045 CHECK(iterator->GetBreakLocation().IsDebuggerStatement());
8046 CHECK_EQ(7, iterator->GetBreakLocation().position());
8047 iterator->Next();
8048 CHECK(iterator->GetBreakLocation().IsDebugBreakSlot());
8049 CHECK_EQ(22, iterator->GetBreakLocation().position());
8050 iterator->Next();
8051 CHECK(iterator->GetBreakLocation().IsCall());
8052 CHECK_EQ(22, iterator->GetBreakLocation().position());
8053 iterator->Next();
8054 CHECK(iterator->GetBreakLocation().IsDebuggerStatement());
8055 CHECK_EQ(37, iterator->GetBreakLocation().position());
8056 iterator->Next();
8057 CHECK(iterator->GetBreakLocation().IsReturn());
8058 CHECK_EQ(50, iterator->GetBreakLocation().position());
8059 iterator->Next();
8060 CHECK(iterator->Done());
8061 delete iterator;
8062
8063 iterator = TestBreakLocation::GetIterator(debug_info, i::CALLS_AND_RETURNS);
8064 CHECK(iterator->GetBreakLocation().IsCall());
8065 CHECK_EQ(22, iterator->GetBreakLocation().position());
8066 iterator->Next();
8067 CHECK(iterator->GetBreakLocation().IsReturn());
8068 CHECK_EQ(50, iterator->GetBreakLocation().position());
8069 iterator->Next();
8070 CHECK(iterator->Done());
8071 delete iterator;
8072
8073 DisableDebugger(isolate);
8074}