blob: 3ed6ec8e2ece275bed4737f7cbaf0ef06f901f84 [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.
Ben Murdochda12d292016-06-02 14:46:10 +01002750 CHECK_EQ(44, 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
Steve Blocka7e24c12009-10-30 11:49:00 +00002891// Test the stepping mechanism with different ICs.
2892TEST(DebugStepLinearMixedICs) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002893 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002894 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002895
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002896 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002897 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002898
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002899 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00002900 // Create a function for testing stepping.
2901 v8::Local<v8::Function> foo = CompileFunction(&env,
2902 "function bar() {};"
2903 "function foo() {"
2904 " var x;"
2905 " var index='name';"
2906 " var y = {};"
2907 " a=1;b=2;x=a;y[index]=3;x=y[index];bar();}", "foo");
Ben Murdochb0fe1622011-05-05 13:52:32 +01002908
2909 // Run functions to allow them to get optimized.
2910 CompileRun("a=0; b=0; bar(); foo();");
2911
Steve Blocka7e24c12009-10-30 11:49:00 +00002912 SetBreakPoint(foo, 0);
2913
Steve Blocka7e24c12009-10-30 11:49:00 +00002914 step_action = StepIn;
2915 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002916 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002917
2918 // With stepping all break locations are hit.
Ben Murdochda12d292016-06-02 14:46:10 +01002919 CHECK_EQ(10, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002920
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002921 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2922 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002923
2924 // Register a debug event listener which just counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002925 v8::Debug::SetDebugEventListener(env->GetIsolate(),
2926 DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00002927
2928 SetBreakPoint(foo, 0);
2929 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002930 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00002931
2932 // Without stepping only active break points are hit.
2933 CHECK_EQ(1, break_point_hit_count);
2934
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002935 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2936 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002937}
2938
2939
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002940TEST(DebugStepDeclarations) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002941 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002942 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002943
2944 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002945 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002946
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002947 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002948 // Create a function for testing stepping. Run it to allow it to get
2949 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002950 const char* src = "function foo() { "
2951 " var a;"
2952 " var b = 1;"
2953 " var c = foo;"
2954 " var d = Math.floor;"
2955 " var e = b + d(1.2);"
Ben Murdochb0fe1622011-05-05 13:52:32 +01002956 "}"
2957 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002958 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
Ben Murdochb0fe1622011-05-05 13:52:32 +01002959
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002960 SetBreakPoint(foo, 0);
2961
2962 // Stepping through the declarations.
2963 step_action = StepIn;
2964 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002965 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Ben Murdochda12d292016-06-02 14:46:10 +01002966 CHECK_EQ(5, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002967
2968 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002969 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
2970 CheckDebuggerUnloaded(env->GetIsolate());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002971}
2972
2973
2974TEST(DebugStepLocals) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002975 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002976 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002977
2978 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002979 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002980
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002981 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01002982 // Create a function for testing stepping. Run it to allow it to get
2983 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002984 const char* src = "function foo() { "
2985 " var a,b;"
2986 " a = 1;"
2987 " b = a + 2;"
2988 " b = 1 + 2 + 3;"
2989 " a = Math.floor(b);"
Ben Murdochb0fe1622011-05-05 13:52:32 +01002990 "}"
2991 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002992 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
Ben Murdochb0fe1622011-05-05 13:52:32 +01002993
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002994 SetBreakPoint(foo, 0);
2995
2996 // Stepping through the declarations.
2997 step_action = StepIn;
2998 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002999 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Ben Murdochda12d292016-06-02 14:46:10 +01003000 CHECK_EQ(5, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003001
3002 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003003 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3004 CheckDebuggerUnloaded(env->GetIsolate());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003005}
3006
3007
Steve Blocka7e24c12009-10-30 11:49:00 +00003008TEST(DebugStepIf) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003009 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003010 v8::Isolate* isolate = env->GetIsolate();
3011 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003012
3013 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003014 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Steve Blocka7e24c12009-10-30 11:49:00 +00003015
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003016 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003017 // Create a function for testing stepping. Run it to allow it to get
3018 // optimized.
Steve Blocka7e24c12009-10-30 11:49:00 +00003019 const int argc = 1;
3020 const char* src = "function foo(x) { "
3021 " a = 1;"
3022 " if (x) {"
3023 " b = 1;"
3024 " } else {"
3025 " c = 1;"
3026 " d = 1;"
3027 " }"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003028 "}"
3029 "a=0; b=0; c=0; d=0; foo()";
Steve Blocka7e24c12009-10-30 11:49:00 +00003030 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3031 SetBreakPoint(foo, 0);
3032
3033 // Stepping through the true part.
3034 step_action = StepIn;
3035 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003036 v8::Local<v8::Value> argv_true[argc] = {v8::True(isolate)};
3037 foo->Call(context, env->Global(), argc, argv_true).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003038 CHECK_EQ(4, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003039
3040 // Stepping through the false part.
3041 step_action = StepIn;
3042 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003043 v8::Local<v8::Value> argv_false[argc] = {v8::False(isolate)};
3044 foo->Call(context, env->Global(), argc, argv_false).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003045 CHECK_EQ(5, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003046
3047 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003048 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3049 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003050}
3051
3052
3053TEST(DebugStepSwitch) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003054 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003055 v8::Isolate* isolate = env->GetIsolate();
3056 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003057
3058 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003059 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
Steve Blocka7e24c12009-10-30 11:49:00 +00003060
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003061 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003062 // Create a function for testing stepping. Run it to allow it to get
3063 // optimized.
Steve Blocka7e24c12009-10-30 11:49:00 +00003064 const int argc = 1;
3065 const char* src = "function foo(x) { "
3066 " a = 1;"
3067 " switch (x) {"
3068 " case 1:"
3069 " b = 1;"
3070 " case 2:"
3071 " c = 1;"
3072 " break;"
3073 " case 3:"
3074 " d = 1;"
3075 " e = 1;"
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003076 " f = 1;"
Steve Blocka7e24c12009-10-30 11:49:00 +00003077 " break;"
3078 " }"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003079 "}"
3080 "a=0; b=0; c=0; d=0; e=0; f=0; foo()";
Steve Blocka7e24c12009-10-30 11:49:00 +00003081 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3082 SetBreakPoint(foo, 0);
3083
3084 // One case with fall-through.
3085 step_action = StepIn;
3086 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003087 v8::Local<v8::Value> argv_1[argc] = {v8::Number::New(isolate, 1)};
3088 foo->Call(context, env->Global(), argc, argv_1).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003089 CHECK_EQ(6, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003090
3091 // Another case.
3092 step_action = StepIn;
3093 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003094 v8::Local<v8::Value> argv_2[argc] = {v8::Number::New(isolate, 2)};
3095 foo->Call(context, env->Global(), argc, argv_2).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003096 CHECK_EQ(5, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003097
3098 // Last case.
3099 step_action = StepIn;
3100 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003101 v8::Local<v8::Value> argv_3[argc] = {v8::Number::New(isolate, 3)};
3102 foo->Call(context, env->Global(), argc, argv_3).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003103 CHECK_EQ(7, break_point_hit_count);
3104
3105 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003106 v8::Debug::SetDebugEventListener(isolate, nullptr);
3107 CheckDebuggerUnloaded(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003108}
3109
3110
3111TEST(DebugStepWhile) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003112 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003113 v8::Isolate* isolate = env->GetIsolate();
3114 v8::HandleScope scope(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003115
3116 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003117 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003118
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003119 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003120 // Create a function for testing stepping. Run it to allow it to get
3121 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003122 const int argc = 1;
3123 const char* src = "function foo(x) { "
3124 " var a = 0;"
3125 " while (a < x) {"
3126 " a++;"
3127 " }"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003128 "}"
3129 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003130 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3131 SetBreakPoint(foo, 8); // "var a = 0;"
3132
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003133 // Looping 0 times. We still should break at the while-condition once.
3134 step_action = StepIn;
3135 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003136 v8::Local<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
3137 foo->Call(context, env->Global(), argc, argv_0).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003138 CHECK_EQ(3, break_point_hit_count);
3139
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003140 // Looping 10 times.
3141 step_action = StepIn;
3142 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003143 v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
3144 foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003145 CHECK_EQ(23, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003146
3147 // Looping 100 times.
3148 step_action = StepIn;
3149 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003150 v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
3151 foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003152 CHECK_EQ(203, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003153
3154 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003155 v8::Debug::SetDebugEventListener(isolate, nullptr);
3156 CheckDebuggerUnloaded(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003157}
3158
3159
3160TEST(DebugStepDoWhile) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003161 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003162 v8::Isolate* isolate = env->GetIsolate();
3163 v8::HandleScope scope(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003164
3165 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003166 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003167
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003168 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003169 // Create a function for testing stepping. Run it to allow it to get
3170 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003171 const int argc = 1;
3172 const char* src = "function foo(x) { "
3173 " var a = 0;"
3174 " do {"
3175 " a++;"
3176 " } while (a < x)"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003177 "}"
3178 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003179 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3180 SetBreakPoint(foo, 8); // "var a = 0;"
3181
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003182 // Looping 0 times.
3183 step_action = StepIn;
3184 break_point_hit_count = 0;
3185 v8::Local<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
3186 foo->Call(context, env->Global(), argc, argv_0).ToLocalChecked();
3187 CHECK_EQ(4, break_point_hit_count);
3188
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003189 // Looping 10 times.
3190 step_action = StepIn;
3191 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003192 v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
3193 foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003194 CHECK_EQ(22, break_point_hit_count);
3195
3196 // Looping 100 times.
3197 step_action = StepIn;
3198 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003199 v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
3200 foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003201 CHECK_EQ(202, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003202
3203 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003204 v8::Debug::SetDebugEventListener(isolate, nullptr);
3205 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003206}
3207
3208
3209TEST(DebugStepFor) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003210 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003211 v8::Isolate* isolate = env->GetIsolate();
3212 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003213
3214 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003215 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
Steve Blocka7e24c12009-10-30 11:49:00 +00003216
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003217 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003218 // Create a function for testing stepping. Run it to allow it to get
3219 // optimized.
Steve Blocka7e24c12009-10-30 11:49:00 +00003220 const int argc = 1;
3221 const char* src = "function foo(x) { "
3222 " a = 1;"
3223 " for (i = 0; i < x; i++) {"
3224 " b = 1;"
3225 " }"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003226 "}"
3227 "a=0; b=0; i=0; foo()";
Steve Blocka7e24c12009-10-30 11:49:00 +00003228 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
Ben Murdochb0fe1622011-05-05 13:52:32 +01003229
Steve Blocka7e24c12009-10-30 11:49:00 +00003230 SetBreakPoint(foo, 8); // "a = 1;"
3231
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003232 // Looping 0 times.
3233 step_action = StepIn;
3234 break_point_hit_count = 0;
3235 v8::Local<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
3236 foo->Call(context, env->Global(), argc, argv_0).ToLocalChecked();
3237 CHECK_EQ(4, break_point_hit_count);
3238
Steve Blocka7e24c12009-10-30 11:49:00 +00003239 // Looping 10 times.
3240 step_action = StepIn;
3241 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003242 v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
3243 foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
3244 CHECK_EQ(34, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003245
3246 // Looping 100 times.
3247 step_action = StepIn;
3248 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003249 v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
3250 foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
3251 CHECK_EQ(304, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003252
3253 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003254 v8::Debug::SetDebugEventListener(isolate, nullptr);
3255 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003256}
3257
3258
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003259TEST(DebugStepForContinue) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003260 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003261 v8::Isolate* isolate = env->GetIsolate();
3262 v8::HandleScope scope(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003263
3264 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003265 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003266
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003267 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003268 // Create a function for testing stepping. Run it to allow it to get
3269 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003270 const int argc = 1;
3271 const char* src = "function foo(x) { "
3272 " var a = 0;"
3273 " var b = 0;"
3274 " var c = 0;"
3275 " for (var i = 0; i < x; i++) {"
3276 " a++;"
3277 " if (a % 2 == 0) continue;"
3278 " b++;"
3279 " c++;"
3280 " }"
3281 " return b;"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003282 "}"
3283 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003284 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003285 v8::Local<v8::Value> result;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003286 SetBreakPoint(foo, 8); // "var a = 0;"
3287
3288 // Each loop generates 4 or 5 steps depending on whether a is equal.
3289
3290 // Looping 10 times.
3291 step_action = StepIn;
3292 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003293 v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
3294 result = foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
3295 CHECK_EQ(5, result->Int32Value(context).FromJust());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003296 CHECK_EQ(62, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003297
3298 // Looping 100 times.
3299 step_action = StepIn;
3300 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003301 v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
3302 result = foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
3303 CHECK_EQ(50, result->Int32Value(context).FromJust());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003304 CHECK_EQ(557, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003305
3306 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003307 v8::Debug::SetDebugEventListener(isolate, nullptr);
3308 CheckDebuggerUnloaded(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003309}
3310
3311
3312TEST(DebugStepForBreak) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003313 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003314 v8::Isolate* isolate = env->GetIsolate();
3315 v8::HandleScope scope(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003316
3317 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003318 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003319
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003320 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003321 // Create a function for testing stepping. Run it to allow it to get
3322 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003323 const int argc = 1;
3324 const char* src = "function foo(x) { "
3325 " var a = 0;"
3326 " var b = 0;"
3327 " var c = 0;"
3328 " for (var i = 0; i < 1000; i++) {"
3329 " a++;"
3330 " if (a == x) break;"
3331 " b++;"
3332 " c++;"
3333 " }"
3334 " return b;"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003335 "}"
3336 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003337 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003338 v8::Local<v8::Value> result;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003339 SetBreakPoint(foo, 8); // "var a = 0;"
3340
3341 // Each loop generates 5 steps except for the last (when break is executed)
3342 // which only generates 4.
3343
3344 // Looping 10 times.
3345 step_action = StepIn;
3346 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003347 v8::Local<v8::Value> argv_10[argc] = {v8::Number::New(isolate, 10)};
3348 result = foo->Call(context, env->Global(), argc, argv_10).ToLocalChecked();
3349 CHECK_EQ(9, result->Int32Value(context).FromJust());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003350 CHECK_EQ(64, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003351
3352 // Looping 100 times.
3353 step_action = StepIn;
3354 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003355 v8::Local<v8::Value> argv_100[argc] = {v8::Number::New(isolate, 100)};
3356 result = foo->Call(context, env->Global(), argc, argv_100).ToLocalChecked();
3357 CHECK_EQ(99, result->Int32Value(context).FromJust());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003358 CHECK_EQ(604, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003359
3360 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003361 v8::Debug::SetDebugEventListener(isolate, nullptr);
3362 CheckDebuggerUnloaded(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003363}
3364
3365
3366TEST(DebugStepForIn) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003367 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003368 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003369
3370 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003371 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003372
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003373 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003374 // Create a function for testing stepping. Run it to allow it to get
3375 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003376 v8::Local<v8::Function> foo;
3377 const char* src_1 = "function foo() { "
3378 " var a = [1, 2];"
3379 " for (x in a) {"
3380 " b = 0;"
3381 " }"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003382 "}"
3383 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003384 foo = CompileFunction(&env, src_1, "foo");
3385 SetBreakPoint(foo, 0); // "var a = ..."
3386
3387 step_action = StepIn;
3388 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003389 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003390 CHECK_EQ(8, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003391
Ben Murdochb0fe1622011-05-05 13:52:32 +01003392 // Create a function for testing stepping. Run it to allow it to get
3393 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003394 const char* src_2 = "function foo() { "
3395 " var a = {a:[1, 2, 3]};"
3396 " for (x in a.a) {"
3397 " b = 0;"
3398 " }"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003399 "}"
3400 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003401 foo = CompileFunction(&env, src_2, "foo");
3402 SetBreakPoint(foo, 0); // "var a = ..."
3403
3404 step_action = StepIn;
3405 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003406 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003407 CHECK_EQ(10, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003408
3409 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003410 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3411 CheckDebuggerUnloaded(env->GetIsolate());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003412}
3413
3414
3415TEST(DebugStepWith) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003416 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003417 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003418
3419 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003420 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003421
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003422 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003423 // Create a function for testing stepping. Run it to allow it to get
3424 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003425 const char* src = "function foo(x) { "
3426 " var a = {};"
3427 " with (a) {}"
3428 " with (b) {}"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003429 "}"
3430 "foo()";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003431 CHECK(env->Global()
3432 ->Set(context, v8_str(env->GetIsolate(), "b"),
3433 v8::Object::New(env->GetIsolate()))
3434 .FromJust());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003435 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003436 v8::Local<v8::Value> result;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003437 SetBreakPoint(foo, 8); // "var a = {};"
3438
3439 step_action = StepIn;
3440 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003441 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003442 CHECK_EQ(4, break_point_hit_count);
3443
3444 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003445 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3446 CheckDebuggerUnloaded(env->GetIsolate());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003447}
3448
3449
3450TEST(DebugConditional) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003451 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003452 v8::Isolate* isolate = env->GetIsolate();
3453 v8::HandleScope scope(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003454
3455 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003456 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003457
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003458 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003459 // Create a function for testing stepping. Run it to allow it to get
3460 // optimized.
Ben Murdochda12d292016-06-02 14:46:10 +01003461 const char* src =
3462 "function foo(x) { "
3463 " return x ? 1 : 2;"
3464 "}"
3465 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003466 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3467 SetBreakPoint(foo, 0); // "var a;"
3468
3469 step_action = StepIn;
3470 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003471 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Ben Murdochda12d292016-06-02 14:46:10 +01003472 CHECK_EQ(2, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003473
3474 step_action = StepIn;
3475 break_point_hit_count = 0;
3476 const int argc = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003477 v8::Local<v8::Value> argv_true[argc] = {v8::True(isolate)};
3478 foo->Call(context, env->Global(), argc, argv_true).ToLocalChecked();
Ben Murdochda12d292016-06-02 14:46:10 +01003479 CHECK_EQ(2, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003480
3481 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003482 v8::Debug::SetDebugEventListener(isolate, nullptr);
3483 CheckDebuggerUnloaded(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003484}
3485
3486
Steve Blocka7e24c12009-10-30 11:49:00 +00003487TEST(StepInOutSimple) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003488 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003489 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003490
3491 // Create a function for checking the function when hitting a break point.
3492 frame_function_name = CompileFunction(&env,
3493 frame_function_name_source,
3494 "frame_function_name");
3495
3496 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003497 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStepSequence);
Steve Blocka7e24c12009-10-30 11:49:00 +00003498
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003499 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003500 // Create a function for testing stepping. Run it to allow it to get
3501 // optimized.
Steve Blocka7e24c12009-10-30 11:49:00 +00003502 const char* src = "function a() {b();c();}; "
3503 "function b() {c();}; "
Ben Murdochb0fe1622011-05-05 13:52:32 +01003504 "function c() {}; "
3505 "a(); b(); c()";
Steve Blocka7e24c12009-10-30 11:49:00 +00003506 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3507 SetBreakPoint(a, 0);
3508
3509 // Step through invocation of a with step in.
3510 step_action = StepIn;
3511 break_point_hit_count = 0;
3512 expected_step_sequence = "abcbaca";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003513 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00003514 CHECK_EQ(StrLength(expected_step_sequence),
3515 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003516
3517 // Step through invocation of a with step next.
3518 step_action = StepNext;
3519 break_point_hit_count = 0;
3520 expected_step_sequence = "aaa";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003521 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00003522 CHECK_EQ(StrLength(expected_step_sequence),
3523 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003524
3525 // Step through invocation of a with step out.
3526 step_action = StepOut;
3527 break_point_hit_count = 0;
3528 expected_step_sequence = "a";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003529 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00003530 CHECK_EQ(StrLength(expected_step_sequence),
3531 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003532
3533 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003534 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3535 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003536}
3537
3538
3539TEST(StepInOutTree) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003540 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003541 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003542
3543 // Create a function for checking the function when hitting a break point.
3544 frame_function_name = CompileFunction(&env,
3545 frame_function_name_source,
3546 "frame_function_name");
3547
3548 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003549 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStepSequence);
Steve Blocka7e24c12009-10-30 11:49:00 +00003550
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003551 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003552 // Create a function for testing stepping. Run it to allow it to get
3553 // optimized.
Steve Blocka7e24c12009-10-30 11:49:00 +00003554 const char* src = "function a() {b(c(d()),d());c(d());d()}; "
3555 "function b(x,y) {c();}; "
3556 "function c(x) {}; "
Ben Murdochb0fe1622011-05-05 13:52:32 +01003557 "function d() {}; "
3558 "a(); b(); c(); d()";
Steve Blocka7e24c12009-10-30 11:49:00 +00003559 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3560 SetBreakPoint(a, 0);
3561
3562 // Step through invocation of a with step in.
3563 step_action = StepIn;
3564 break_point_hit_count = 0;
3565 expected_step_sequence = "adacadabcbadacada";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003566 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00003567 CHECK_EQ(StrLength(expected_step_sequence),
3568 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003569
3570 // Step through invocation of a with step next.
3571 step_action = StepNext;
3572 break_point_hit_count = 0;
3573 expected_step_sequence = "aaaa";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003574 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00003575 CHECK_EQ(StrLength(expected_step_sequence),
3576 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003577
3578 // Step through invocation of a with step out.
3579 step_action = StepOut;
3580 break_point_hit_count = 0;
3581 expected_step_sequence = "a";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003582 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00003583 CHECK_EQ(StrLength(expected_step_sequence),
3584 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003585
3586 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003587 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3588 CheckDebuggerUnloaded(env->GetIsolate(), true);
Steve Blocka7e24c12009-10-30 11:49:00 +00003589}
3590
3591
3592TEST(StepInOutBranch) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003593 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003594 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003595
3596 // Create a function for checking the function when hitting a break point.
3597 frame_function_name = CompileFunction(&env,
3598 frame_function_name_source,
3599 "frame_function_name");
3600
3601 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003602 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStepSequence);
Steve Blocka7e24c12009-10-30 11:49:00 +00003603
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003604 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01003605 // Create a function for testing stepping. Run it to allow it to get
3606 // optimized.
Steve Blocka7e24c12009-10-30 11:49:00 +00003607 const char* src = "function a() {b(false);c();}; "
3608 "function b(x) {if(x){c();};}; "
Ben Murdochb0fe1622011-05-05 13:52:32 +01003609 "function c() {}; "
3610 "a(); b(); c()";
Steve Blocka7e24c12009-10-30 11:49:00 +00003611 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3612 SetBreakPoint(a, 0);
3613
3614 // Step through invocation of a.
3615 step_action = StepIn;
3616 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003617 expected_step_sequence = "abbaca";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003618 a->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00003619 CHECK_EQ(StrLength(expected_step_sequence),
3620 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003621
3622 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003623 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3624 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003625}
3626
3627
3628// Test that step in does not step into native functions.
3629TEST(DebugStepNatives) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003630 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003631 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003632
3633 // Create a function for testing stepping.
3634 v8::Local<v8::Function> foo = CompileFunction(
3635 &env,
3636 "function foo(){debugger;Math.sin(1);}",
3637 "foo");
3638
3639 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003640 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Steve Blocka7e24c12009-10-30 11:49:00 +00003641
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003642 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00003643 step_action = StepIn;
3644 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003645 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00003646
3647 // With stepping all break locations are hit.
3648 CHECK_EQ(3, break_point_hit_count);
3649
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003650 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3651 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003652
3653 // Register a debug event listener which just counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003654 v8::Debug::SetDebugEventListener(env->GetIsolate(),
3655 DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00003656
3657 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003658 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00003659
3660 // Without stepping only active break points are hit.
3661 CHECK_EQ(1, break_point_hit_count);
3662
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003663 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3664 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003665}
3666
3667
3668// Test that step in works with function.apply.
3669TEST(DebugStepFunctionApply) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003670 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003671 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003672
3673 // Create a function for testing stepping.
3674 v8::Local<v8::Function> foo = CompileFunction(
3675 &env,
3676 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3677 "function foo(){ debugger; bar.apply(this, [1,2,3]); }",
3678 "foo");
3679
3680 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003681 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStep);
Steve Blocka7e24c12009-10-30 11:49:00 +00003682
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003683 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00003684 step_action = StepIn;
3685 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003686 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00003687
3688 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003689 CHECK_EQ(7, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003690
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003691 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3692 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003693
3694 // Register a debug event listener which just counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003695 v8::Debug::SetDebugEventListener(env->GetIsolate(),
3696 DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00003697
3698 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003699 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00003700
3701 // Without stepping only the debugger statement is hit.
3702 CHECK_EQ(1, break_point_hit_count);
3703
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003704 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3705 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003706}
3707
3708
3709// Test that step in works with function.call.
3710TEST(DebugStepFunctionCall) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003711 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003712 v8::Isolate* isolate = env->GetIsolate();
3713 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003714
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003715 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00003716 // Create a function for testing stepping.
3717 v8::Local<v8::Function> foo = CompileFunction(
3718 &env,
3719 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3720 "function foo(a){ debugger;"
3721 " if (a) {"
3722 " bar.call(this, 1, 2, 3);"
3723 " } else {"
3724 " bar.call(this, 0);"
3725 " }"
3726 "}",
3727 "foo");
3728
3729 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003730 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
Steve Blocka7e24c12009-10-30 11:49:00 +00003731 step_action = StepIn;
3732
3733 // Check stepping where the if condition in bar is false.
3734 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003735 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003736 CHECK_EQ(6, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003737
3738 // Check stepping where the if condition in bar is true.
3739 break_point_hit_count = 0;
3740 const int argc = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003741 v8::Local<v8::Value> argv[argc] = {v8::True(isolate)};
3742 foo->Call(context, env->Global(), argc, argv).ToLocalChecked();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003743 CHECK_EQ(8, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003744
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003745 v8::Debug::SetDebugEventListener(isolate, nullptr);
3746 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003747
3748 // Register a debug event listener which just counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003749 v8::Debug::SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00003750
3751 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003752 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00003753
3754 // Without stepping only the debugger statement is hit.
3755 CHECK_EQ(1, break_point_hit_count);
3756
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003757 v8::Debug::SetDebugEventListener(isolate, nullptr);
3758 CheckDebuggerUnloaded(isolate);
3759}
3760
3761
3762// Test that step in works with Function.call.apply.
3763TEST(DebugStepFunctionCallApply) {
3764 DebugLocalContext env;
3765 v8::Isolate* isolate = env->GetIsolate();
3766 v8::HandleScope scope(isolate);
3767
3768 v8::Local<v8::Context> context = env.context();
3769 // Create a function for testing stepping.
3770 v8::Local<v8::Function> foo =
3771 CompileFunction(&env,
3772 "function bar() { }"
3773 "function foo(){ debugger;"
3774 " Function.call.apply(bar);"
3775 " Function.call.apply(Function.call, "
3776 "[Function.call, bar]);"
3777 "}",
3778 "foo");
3779
3780 // Register a debug event listener which steps and counts.
3781 v8::Debug::SetDebugEventListener(isolate, DebugEventStep);
3782 step_action = StepIn;
3783
3784 break_point_hit_count = 0;
3785 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3786 CHECK_EQ(6, break_point_hit_count);
3787
3788 v8::Debug::SetDebugEventListener(isolate, nullptr);
3789 CheckDebuggerUnloaded(isolate);
3790
3791 // Register a debug event listener which just counts.
3792 v8::Debug::SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
3793
3794 break_point_hit_count = 0;
3795 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3796
3797 // Without stepping only the debugger statement is hit.
3798 CHECK_EQ(1, break_point_hit_count);
3799
3800 v8::Debug::SetDebugEventListener(isolate, nullptr);
3801 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003802}
3803
3804
Steve Blockd0582a62009-12-15 09:54:21 +00003805// Tests that breakpoint will be hit if it's set in script.
3806TEST(PauseInScript) {
Steve Blockd0582a62009-12-15 09:54:21 +00003807 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003808 v8::HandleScope scope(env->GetIsolate());
Steve Blockd0582a62009-12-15 09:54:21 +00003809 env.ExposeDebug();
3810
3811 // Register a debug event listener which counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003812 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
Steve Blockd0582a62009-12-15 09:54:21 +00003813
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003814 v8::Local<v8::Context> context = env.context();
Steve Blockd0582a62009-12-15 09:54:21 +00003815 // Create a script that returns a function.
3816 const char* src = "(function (evt) {})";
3817 const char* script_name = "StepInHandlerTest";
3818
3819 // Set breakpoint in the script.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003820 SetScriptBreakPointByNameFromJS(env->GetIsolate(), script_name, 0, -1);
Steve Blockd0582a62009-12-15 09:54:21 +00003821 break_point_hit_count = 0;
3822
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003823 v8::ScriptOrigin origin(v8_str(env->GetIsolate(), script_name),
3824 v8::Integer::New(env->GetIsolate(), 0));
3825 v8::Local<v8::Script> script =
3826 v8::Script::Compile(context, v8_str(env->GetIsolate(), src), &origin)
3827 .ToLocalChecked();
3828 v8::Local<v8::Value> r = script->Run(context).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00003829
3830 CHECK(r->IsFunction());
3831 CHECK_EQ(1, break_point_hit_count);
3832
3833 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003834 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3835 CheckDebuggerUnloaded(env->GetIsolate());
3836}
3837
3838
3839static void DebugEventCounterCheck(int caught, int uncaught, int message) {
3840 CHECK_EQ(caught, exception_hit_count);
3841 CHECK_EQ(uncaught, uncaught_exception_hit_count);
3842 CHECK_EQ(message, message_callback_count);
Steve Blockd0582a62009-12-15 09:54:21 +00003843}
3844
3845
Steve Blocka7e24c12009-10-30 11:49:00 +00003846// Test break on exceptions. For each exception break combination the number
3847// of debug event exception callbacks and message callbacks are collected. The
3848// number of debug event exception callbacks are used to check that the
3849// debugger is called correctly and the number of message callbacks is used to
3850// check that uncaught exceptions are still returned even if there is a break
3851// for them.
3852TEST(BreakOnException) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003853 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003854 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003855 env.ExposeDebug();
3856
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003857 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00003858 // Create functions for testing break on exception.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003859 CompileFunction(&env, "function throws(){throw 1;}", "throws");
Steve Blocka7e24c12009-10-30 11:49:00 +00003860 v8::Local<v8::Function> caught =
3861 CompileFunction(&env,
3862 "function caught(){try {throws();} catch(e) {};}",
3863 "caught");
3864 v8::Local<v8::Function> notCaught =
3865 CompileFunction(&env, "function notCaught(){throws();}", "notCaught");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003866 v8::Local<v8::Function> notCaughtFinally = CompileFunction(
3867 &env, "function notCaughtFinally(){try{throws();}finally{}}",
3868 "notCaughtFinally");
3869 // In this edge case, even though this finally does not propagate the
3870 // exception, the debugger considers this uncaught, since we want to break
3871 // at the first throw for the general case where finally implicitly rethrows.
3872 v8::Local<v8::Function> edgeCaseFinally = CompileFunction(
3873 &env, "function caughtFinally(){L:try{throws();}finally{break L;}}",
3874 "caughtFinally");
Steve Blocka7e24c12009-10-30 11:49:00 +00003875
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003876 env->GetIsolate()->AddMessageListener(MessageCallbackCount);
3877 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
Steve Blocka7e24c12009-10-30 11:49:00 +00003878
Ben Murdoch086aeea2011-05-13 15:57:08 +01003879 // Initial state should be no break on exceptions.
Steve Blocka7e24c12009-10-30 11:49:00 +00003880 DebugEventCounterClear();
3881 MessageCallbackCountClear();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003882 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3883 DebugEventCounterCheck(0, 0, 0);
3884 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3885 DebugEventCounterCheck(0, 0, 1);
3886 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3887 DebugEventCounterCheck(0, 0, 2);
3888 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3889 DebugEventCounterCheck(0, 0, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003890
3891 // No break on exception
3892 DebugEventCounterClear();
3893 MessageCallbackCountClear();
3894 ChangeBreakOnException(false, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003895 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3896 DebugEventCounterCheck(0, 0, 0);
3897 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3898 DebugEventCounterCheck(0, 0, 1);
3899 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3900 DebugEventCounterCheck(0, 0, 2);
3901 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3902 DebugEventCounterCheck(0, 0, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003903
3904 // Break on uncaught exception
3905 DebugEventCounterClear();
3906 MessageCallbackCountClear();
3907 ChangeBreakOnException(false, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003908 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3909 DebugEventCounterCheck(0, 0, 0);
3910 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3911 DebugEventCounterCheck(1, 1, 1);
3912 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3913 DebugEventCounterCheck(2, 2, 2);
3914 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3915 DebugEventCounterCheck(3, 3, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003916
3917 // Break on exception and uncaught exception
3918 DebugEventCounterClear();
3919 MessageCallbackCountClear();
3920 ChangeBreakOnException(true, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003921 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3922 DebugEventCounterCheck(1, 0, 0);
3923 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3924 DebugEventCounterCheck(2, 1, 1);
3925 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3926 DebugEventCounterCheck(3, 2, 2);
3927 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3928 DebugEventCounterCheck(4, 3, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003929
3930 // Break on exception
3931 DebugEventCounterClear();
3932 MessageCallbackCountClear();
3933 ChangeBreakOnException(true, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003934 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3935 DebugEventCounterCheck(1, 0, 0);
3936 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3937 DebugEventCounterCheck(2, 1, 1);
3938 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3939 DebugEventCounterCheck(3, 2, 2);
3940 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3941 DebugEventCounterCheck(4, 3, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003942
3943 // No break on exception using JavaScript
3944 DebugEventCounterClear();
3945 MessageCallbackCountClear();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003946 ChangeBreakOnExceptionFromJS(env->GetIsolate(), false, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003947 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3948 DebugEventCounterCheck(0, 0, 0);
3949 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3950 DebugEventCounterCheck(0, 0, 1);
3951 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3952 DebugEventCounterCheck(0, 0, 2);
3953 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3954 DebugEventCounterCheck(0, 0, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003955
3956 // Break on uncaught exception using JavaScript
3957 DebugEventCounterClear();
3958 MessageCallbackCountClear();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003959 ChangeBreakOnExceptionFromJS(env->GetIsolate(), false, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003960 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3961 DebugEventCounterCheck(0, 0, 0);
3962 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3963 DebugEventCounterCheck(1, 1, 1);
3964 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3965 DebugEventCounterCheck(2, 2, 2);
3966 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3967 DebugEventCounterCheck(3, 3, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003968
3969 // Break on exception and uncaught exception using JavaScript
3970 DebugEventCounterClear();
3971 MessageCallbackCountClear();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003972 ChangeBreakOnExceptionFromJS(env->GetIsolate(), true, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003973 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3974 DebugEventCounterCheck(1, 0, 0);
3975 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3976 DebugEventCounterCheck(2, 1, 1);
3977 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3978 DebugEventCounterCheck(3, 2, 2);
3979 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3980 DebugEventCounterCheck(4, 3, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003981
3982 // Break on exception using JavaScript
3983 DebugEventCounterClear();
3984 MessageCallbackCountClear();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003985 ChangeBreakOnExceptionFromJS(env->GetIsolate(), true, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003986 caught->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3987 DebugEventCounterCheck(1, 0, 0);
3988 CHECK(notCaught->Call(context, env->Global(), 0, NULL).IsEmpty());
3989 DebugEventCounterCheck(2, 1, 1);
3990 CHECK(notCaughtFinally->Call(context, env->Global(), 0, NULL).IsEmpty());
3991 DebugEventCounterCheck(3, 2, 2);
3992 edgeCaseFinally->Call(context, env->Global(), 0, NULL).ToLocalChecked();
3993 DebugEventCounterCheck(4, 3, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003994
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003995 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
3996 CheckDebuggerUnloaded(env->GetIsolate());
3997 env->GetIsolate()->RemoveMessageListeners(MessageCallbackCount);
3998}
3999
4000
4001static void try_finally_original_message(v8::Local<v8::Message> message,
4002 v8::Local<v8::Value> data) {
4003 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
4004 CHECK_EQ(2, message->GetLineNumber(context).FromJust());
4005 CHECK_EQ(2, message->GetStartColumn(context).FromJust());
4006 message_callback_count++;
4007}
4008
4009
4010TEST(TryFinallyOriginalMessage) {
4011 // Test that the debugger plays nicely with the pending message.
4012 message_callback_count = 0;
4013 DebugEventCounterClear();
4014 DebugLocalContext env;
4015 v8::Isolate* isolate = CcTest::isolate();
4016 isolate->AddMessageListener(try_finally_original_message);
4017 v8::Debug::SetDebugEventListener(isolate, DebugEventCounter);
4018 ChangeBreakOnException(true, true);
4019 v8::HandleScope scope(isolate);
4020 CompileRun(
4021 "try {\n"
4022 " throw 1;\n"
4023 "} finally {\n"
4024 "}\n");
4025 DebugEventCounterCheck(1, 1, 1);
4026 v8::Debug::SetDebugEventListener(isolate, nullptr);
4027 isolate->RemoveMessageListeners(try_finally_original_message);
Steve Blocka7e24c12009-10-30 11:49:00 +00004028}
4029
4030
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004031TEST(EvalJSInDebugEventListenerOnNativeReThrownException) {
4032 DebugLocalContext env;
4033 v8::HandleScope scope(env->GetIsolate());
4034 env.ExposeDebug();
4035
4036 // Create functions for testing break on exception.
4037 v8::Local<v8::Function> noThrowJS = CompileFunction(
4038 &env, "function noThrowJS(){var a=[1]; a.push(2); return a.length;}",
4039 "noThrowJS");
4040
4041 debug_event_listener_callback = noThrowJS;
4042 debug_event_listener_callback_result = 2;
4043
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004044 env->GetIsolate()->AddMessageListener(MessageCallbackCount);
4045 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004046 // Break on uncaught exception
4047 ChangeBreakOnException(false, true);
4048 DebugEventCounterClear();
4049 MessageCallbackCountClear();
4050
4051 // ReThrow native error
4052 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004053 v8::TryCatch tryCatch(env->GetIsolate());
4054 env->GetIsolate()->ThrowException(
4055 v8::Exception::TypeError(v8_str(env->GetIsolate(), "Type error")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004056 CHECK(tryCatch.HasCaught());
4057 tryCatch.ReThrow();
4058 }
4059 CHECK_EQ(1, exception_hit_count);
4060 CHECK_EQ(1, uncaught_exception_hit_count);
4061 CHECK_EQ(0, message_callback_count); // FIXME: Should it be 1 ?
4062 CHECK(!debug_event_listener_callback.IsEmpty());
4063
4064 debug_event_listener_callback.Clear();
4065}
4066
4067
Steve Blocka7e24c12009-10-30 11:49:00 +00004068// Test break on exception from compiler errors. When compiling using
4069// v8::Script::Compile there is no JavaScript stack whereas when compiling using
4070// eval there are JavaScript frames.
4071TEST(BreakOnCompileException) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004072 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004073 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004074
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004075 v8::Local<v8::Context> context = env.context();
Ben Murdoch086aeea2011-05-13 15:57:08 +01004076 // For this test, we want to break on uncaught exceptions:
4077 ChangeBreakOnException(false, true);
4078
Steve Blocka7e24c12009-10-30 11:49:00 +00004079 // Create a function for checking the function when hitting a break point.
4080 frame_count = CompileFunction(&env, frame_count_source, "frame_count");
4081
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004082 env->GetIsolate()->AddMessageListener(MessageCallbackCount);
4083 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
Steve Blocka7e24c12009-10-30 11:49:00 +00004084
4085 DebugEventCounterClear();
4086 MessageCallbackCountClear();
4087
4088 // Check initial state.
4089 CHECK_EQ(0, exception_hit_count);
4090 CHECK_EQ(0, uncaught_exception_hit_count);
4091 CHECK_EQ(0, message_callback_count);
4092 CHECK_EQ(-1, last_js_stack_height);
4093
4094 // Throws SyntaxError: Unexpected end of input
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004095 CHECK(
4096 v8::Script::Compile(context, v8_str(env->GetIsolate(), "+++")).IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00004097 CHECK_EQ(1, exception_hit_count);
4098 CHECK_EQ(1, uncaught_exception_hit_count);
4099 CHECK_EQ(1, message_callback_count);
4100 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
4101
4102 // Throws SyntaxError: Unexpected identifier
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004103 CHECK(
4104 v8::Script::Compile(context, v8_str(env->GetIsolate(), "x x")).IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00004105 CHECK_EQ(2, exception_hit_count);
4106 CHECK_EQ(2, uncaught_exception_hit_count);
4107 CHECK_EQ(2, message_callback_count);
4108 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
4109
4110 // Throws SyntaxError: Unexpected end of input
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004111 CHECK(v8::Script::Compile(context, v8_str(env->GetIsolate(), "eval('+++')"))
4112 .ToLocalChecked()
4113 ->Run(context)
4114 .IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00004115 CHECK_EQ(3, exception_hit_count);
4116 CHECK_EQ(3, uncaught_exception_hit_count);
4117 CHECK_EQ(3, message_callback_count);
4118 CHECK_EQ(1, last_js_stack_height);
4119
4120 // Throws SyntaxError: Unexpected identifier
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004121 CHECK(v8::Script::Compile(context, v8_str(env->GetIsolate(), "eval('x x')"))
4122 .ToLocalChecked()
4123 ->Run(context)
4124 .IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00004125 CHECK_EQ(4, exception_hit_count);
4126 CHECK_EQ(4, uncaught_exception_hit_count);
4127 CHECK_EQ(4, message_callback_count);
4128 CHECK_EQ(1, last_js_stack_height);
4129}
4130
4131
4132TEST(StepWithException) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004133 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004134 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004135
Ben Murdoch086aeea2011-05-13 15:57:08 +01004136 // For this test, we want to break on uncaught exceptions:
4137 ChangeBreakOnException(false, true);
4138
Steve Blocka7e24c12009-10-30 11:49:00 +00004139 // Create a function for checking the function when hitting a break point.
4140 frame_function_name = CompileFunction(&env,
4141 frame_function_name_source,
4142 "frame_function_name");
4143
4144 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004145 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStepSequence);
Steve Blocka7e24c12009-10-30 11:49:00 +00004146
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004147 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00004148 // Create functions for testing stepping.
4149 const char* src = "function a() { n(); }; "
4150 "function b() { c(); }; "
4151 "function c() { n(); }; "
4152 "function d() { x = 1; try { e(); } catch(x) { x = 2; } }; "
4153 "function e() { n(); }; "
4154 "function f() { x = 1; try { g(); } catch(x) { x = 2; } }; "
4155 "function g() { h(); }; "
4156 "function h() { x = 1; throw 1; }; ";
4157
4158 // Step through invocation of a.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004159 ClearStepping();
Steve Blocka7e24c12009-10-30 11:49:00 +00004160 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
4161 SetBreakPoint(a, 0);
4162 step_action = StepIn;
4163 break_point_hit_count = 0;
4164 expected_step_sequence = "aa";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004165 CHECK(a->Call(context, env->Global(), 0, NULL).IsEmpty());
Steve Blockd0582a62009-12-15 09:54:21 +00004166 CHECK_EQ(StrLength(expected_step_sequence),
4167 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004168
4169 // Step through invocation of b + c.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004170 ClearStepping();
Steve Blocka7e24c12009-10-30 11:49:00 +00004171 v8::Local<v8::Function> b = CompileFunction(&env, src, "b");
4172 SetBreakPoint(b, 0);
4173 step_action = StepIn;
4174 break_point_hit_count = 0;
4175 expected_step_sequence = "bcc";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004176 CHECK(b->Call(context, env->Global(), 0, NULL).IsEmpty());
Steve Blockd0582a62009-12-15 09:54:21 +00004177 CHECK_EQ(StrLength(expected_step_sequence),
4178 break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004179
Steve Blocka7e24c12009-10-30 11:49:00 +00004180 // Step through invocation of d + e.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004181 ClearStepping();
Steve Blocka7e24c12009-10-30 11:49:00 +00004182 v8::Local<v8::Function> d = CompileFunction(&env, src, "d");
4183 SetBreakPoint(d, 0);
4184 ChangeBreakOnException(false, true);
4185 step_action = StepIn;
4186 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004187 expected_step_sequence = "ddedd";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004188 d->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00004189 CHECK_EQ(StrLength(expected_step_sequence),
4190 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004191
4192 // Step through invocation of d + e now with break on caught exceptions.
4193 ChangeBreakOnException(true, true);
4194 step_action = StepIn;
4195 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004196 expected_step_sequence = "ddeedd";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004197 d->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00004198 CHECK_EQ(StrLength(expected_step_sequence),
4199 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004200
4201 // Step through invocation of f + g + h.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004202 ClearStepping();
Steve Blocka7e24c12009-10-30 11:49:00 +00004203 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
4204 SetBreakPoint(f, 0);
4205 ChangeBreakOnException(false, true);
4206 step_action = StepIn;
4207 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004208 expected_step_sequence = "ffghhff";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004209 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00004210 CHECK_EQ(StrLength(expected_step_sequence),
4211 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004212
4213 // Step through invocation of f + g + h now with break on caught exceptions.
4214 ChangeBreakOnException(true, true);
4215 step_action = StepIn;
4216 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004217 expected_step_sequence = "ffghhhff";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004218 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00004219 CHECK_EQ(StrLength(expected_step_sequence),
4220 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004221
4222 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004223 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
4224 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004225}
4226
4227
4228TEST(DebugBreak) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004229 i::FLAG_stress_compaction = false;
4230#ifdef VERIFY_HEAP
4231 i::FLAG_verify_heap = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00004232#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004233 DebugLocalContext env;
4234 v8::Isolate* isolate = env->GetIsolate();
4235 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004236
4237 // Register a debug event listener which sets the break flag and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004238 v8::Debug::SetDebugEventListener(isolate, DebugEventBreak);
Steve Blocka7e24c12009-10-30 11:49:00 +00004239
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004240 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00004241 // Create a function for testing stepping.
4242 const char* src = "function f0() {}"
4243 "function f1(x1) {}"
4244 "function f2(x1,x2) {}"
4245 "function f3(x1,x2,x3) {}";
4246 v8::Local<v8::Function> f0 = CompileFunction(&env, src, "f0");
4247 v8::Local<v8::Function> f1 = CompileFunction(&env, src, "f1");
4248 v8::Local<v8::Function> f2 = CompileFunction(&env, src, "f2");
4249 v8::Local<v8::Function> f3 = CompileFunction(&env, src, "f3");
4250
4251 // Call the function to make sure it is compiled.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004252 v8::Local<v8::Value> argv[] = {
4253 v8::Number::New(isolate, 1), v8::Number::New(isolate, 1),
4254 v8::Number::New(isolate, 1), v8::Number::New(isolate, 1)};
Steve Blocka7e24c12009-10-30 11:49:00 +00004255
4256 // Call all functions to make sure that they are compiled.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004257 f0->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4258 f1->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4259 f2->Call(context, env->Global(), 0, NULL).ToLocalChecked();
4260 f3->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00004261
4262 // Set the debug break flag.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004263 v8::Debug::DebugBreak(env->GetIsolate());
4264 CHECK(v8::Debug::CheckDebugBreak(env->GetIsolate()));
Steve Blocka7e24c12009-10-30 11:49:00 +00004265
4266 // Call all functions with different argument count.
4267 break_point_hit_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004268 for (unsigned int i = 0; i < arraysize(argv); i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004269 f0->Call(context, env->Global(), i, argv).ToLocalChecked();
4270 f1->Call(context, env->Global(), i, argv).ToLocalChecked();
4271 f2->Call(context, env->Global(), i, argv).ToLocalChecked();
4272 f3->Call(context, env->Global(), i, argv).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00004273 }
4274
4275 // One break for each function called.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004276 CHECK(4 * arraysize(argv) == break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004277
4278 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004279 v8::Debug::SetDebugEventListener(isolate, nullptr);
4280 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004281}
4282
4283
4284// Test to ensure that JavaScript code keeps running while the debug break
4285// through the stack limit flag is set but breaks are disabled.
4286TEST(DisableBreak) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004287 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004288 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004289
4290 // Register a debug event listener which sets the break flag and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004291 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
Steve Blocka7e24c12009-10-30 11:49:00 +00004292
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004293 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00004294 // Create a function for testing stepping.
4295 const char* src = "function f() {g()};function g(){i=0; while(i<10){i++}}";
4296 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
4297
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004298 // Set, test and cancel debug break.
4299 v8::Debug::DebugBreak(env->GetIsolate());
4300 CHECK(v8::Debug::CheckDebugBreak(env->GetIsolate()));
4301 v8::Debug::CancelDebugBreak(env->GetIsolate());
4302 CHECK(!v8::Debug::CheckDebugBreak(env->GetIsolate()));
4303
Steve Blocka7e24c12009-10-30 11:49:00 +00004304 // Set the debug break flag.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004305 v8::Debug::DebugBreak(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004306
4307 // Call all functions with different argument count.
4308 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004309 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00004310 CHECK_EQ(1, break_point_hit_count);
4311
4312 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004313 v8::Debug::DebugBreak(env->GetIsolate());
4314 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
4315 v8::internal::DisableBreak disable_break(isolate->debug(), true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004316 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00004317 CHECK_EQ(1, break_point_hit_count);
4318 }
4319
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004320 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00004321 CHECK_EQ(2, break_point_hit_count);
4322
4323 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004324 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
4325 CheckDebuggerUnloaded(env->GetIsolate());
4326}
4327
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004328TEST(DisableDebuggerStatement) {
4329 DebugLocalContext env;
4330 v8::HandleScope scope(env->GetIsolate());
4331
4332 // Register a debug event listener which sets the break flag and counts.
4333 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventCounter);
4334 CompileRun("debugger;");
4335 CHECK_EQ(1, break_point_hit_count);
4336
4337 // Check that we ignore debugger statement when breakpoints aren't active.
4338 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
4339 isolate->debug()->set_break_points_active(false);
4340 CompileRun("debugger;");
4341 CHECK_EQ(1, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004342}
4343
Leon Clarkee46be812010-01-19 14:06:41 +00004344static const char* kSimpleExtensionSource =
4345 "(function Foo() {"
4346 " return 4;"
4347 "})() ";
4348
4349// http://crbug.com/28933
4350// Test that debug break is disabled when bootstrapper is active.
4351TEST(NoBreakWhenBootstrapping) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004352 v8::Isolate* isolate = CcTest::isolate();
4353 v8::HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00004354
4355 // Register a debug event listener which sets the break flag and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004356 v8::Debug::SetDebugEventListener(isolate, DebugEventCounter);
Leon Clarkee46be812010-01-19 14:06:41 +00004357
4358 // Set the debug break flag.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004359 v8::Debug::DebugBreak(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00004360 break_point_hit_count = 0;
4361 {
4362 // Create a context with an extension to make sure that some JavaScript
4363 // code is executed during bootstrapping.
4364 v8::RegisterExtension(new v8::Extension("simpletest",
4365 kSimpleExtensionSource));
4366 const char* extension_names[] = { "simpletest" };
4367 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004368 v8::HandleScope handle_scope(isolate);
4369 v8::Context::New(isolate, &extensions);
Leon Clarkee46be812010-01-19 14:06:41 +00004370 }
4371 // Check that no DebugBreak events occured during the context creation.
4372 CHECK_EQ(0, break_point_hit_count);
4373
4374 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004375 v8::Debug::SetDebugEventListener(isolate, nullptr);
4376 CheckDebuggerUnloaded(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00004377}
Steve Blocka7e24c12009-10-30 11:49:00 +00004378
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004379
4380static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004381 v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
4382 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
4383 CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 0),
4384 v8_str(info.GetIsolate(), "a"))
4385 .FromJust());
4386 CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 1),
4387 v8_str(info.GetIsolate(), "b"))
4388 .FromJust());
4389 CHECK(result->Set(context, v8::Integer::New(info.GetIsolate(), 2),
4390 v8_str(info.GetIsolate(), "c"))
4391 .FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004392 info.GetReturnValue().Set(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00004393}
4394
4395
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004396static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
4397 v8::Isolate* isolate = info.GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004398 v8::Local<v8::Array> result = v8::Array::New(isolate, 2);
4399 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
4400 CHECK(result->Set(context, v8::Integer::New(isolate, 0),
4401 v8::Number::New(isolate, 1))
4402 .FromJust());
4403 CHECK(result->Set(context, v8::Integer::New(isolate, 1),
4404 v8::Number::New(isolate, 10))
4405 .FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004406 info.GetReturnValue().Set(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00004407}
4408
4409
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004410static void NamedGetter(v8::Local<v8::Name> name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004411 const v8::PropertyCallbackInfo<v8::Value>& info) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004412 if (name->IsSymbol()) return;
4413 v8::String::Utf8Value n(v8::Local<v8::String>::Cast(name));
Steve Blocka7e24c12009-10-30 11:49:00 +00004414 if (strcmp(*n, "a") == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004415 info.GetReturnValue().Set(v8_str(info.GetIsolate(), "AA"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004416 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00004417 } else if (strcmp(*n, "b") == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004418 info.GetReturnValue().Set(v8_str(info.GetIsolate(), "BB"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004419 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00004420 } else if (strcmp(*n, "c") == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004421 info.GetReturnValue().Set(v8_str(info.GetIsolate(), "CC"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004422 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00004423 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004424 info.GetReturnValue().SetUndefined();
4425 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00004426 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004427 info.GetReturnValue().Set(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00004428}
4429
4430
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004431static void IndexedGetter(uint32_t index,
4432 const v8::PropertyCallbackInfo<v8::Value>& info) {
4433 info.GetReturnValue().Set(static_cast<double>(index + 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00004434}
4435
4436
4437TEST(InterceptorPropertyMirror) {
4438 // Create a V8 environment with debug access.
Steve Blocka7e24c12009-10-30 11:49:00 +00004439 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004440 v8::Isolate* isolate = env->GetIsolate();
4441 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004442 env.ExposeDebug();
4443
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004444 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00004445 // Create object with named interceptor.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004446 v8::Local<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004447 named->SetHandler(v8::NamedPropertyHandlerConfiguration(
4448 NamedGetter, NULL, NULL, NULL, NamedEnum));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004449 CHECK(env->Global()
4450 ->Set(context, v8_str(isolate, "intercepted_named"),
4451 named->NewInstance(context).ToLocalChecked())
4452 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004453
4454 // Create object with indexed interceptor.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004455 v8::Local<v8::ObjectTemplate> indexed = v8::ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004456 indexed->SetHandler(v8::IndexedPropertyHandlerConfiguration(
4457 IndexedGetter, NULL, NULL, NULL, IndexedEnum));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004458 CHECK(env->Global()
4459 ->Set(context, v8_str(isolate, "intercepted_indexed"),
4460 indexed->NewInstance(context).ToLocalChecked())
4461 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004462
4463 // Create object with both named and indexed interceptor.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004464 v8::Local<v8::ObjectTemplate> both = v8::ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004465 both->SetHandler(v8::NamedPropertyHandlerConfiguration(
4466 NamedGetter, NULL, NULL, NULL, NamedEnum));
4467 both->SetHandler(v8::IndexedPropertyHandlerConfiguration(
4468 IndexedGetter, NULL, NULL, NULL, IndexedEnum));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004469 CHECK(env->Global()
4470 ->Set(context, v8_str(isolate, "intercepted_both"),
4471 both->NewInstance(context).ToLocalChecked())
4472 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004473
4474 // Get mirrors for the three objects with interceptor.
4475 CompileRun(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004476 "var named_mirror = debug.MakeMirror(intercepted_named);"
4477 "var indexed_mirror = debug.MakeMirror(intercepted_indexed);"
4478 "var both_mirror = debug.MakeMirror(intercepted_both)");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004479 CHECK(CompileRun("named_mirror instanceof debug.ObjectMirror")
4480 ->BooleanValue(context)
4481 .FromJust());
4482 CHECK(CompileRun("indexed_mirror instanceof debug.ObjectMirror")
4483 ->BooleanValue(context)
4484 .FromJust());
4485 CHECK(CompileRun("both_mirror instanceof debug.ObjectMirror")
4486 ->BooleanValue(context)
4487 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004488
4489 // Get the property names from the interceptors
4490 CompileRun(
4491 "named_names = named_mirror.propertyNames();"
4492 "indexed_names = indexed_mirror.propertyNames();"
4493 "both_names = both_mirror.propertyNames()");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004494 CHECK_EQ(3, CompileRun("named_names.length")->Int32Value(context).FromJust());
4495 CHECK_EQ(2,
4496 CompileRun("indexed_names.length")->Int32Value(context).FromJust());
4497 CHECK_EQ(5, CompileRun("both_names.length")->Int32Value(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004498
4499 // Check the expected number of properties.
4500 const char* source;
4501 source = "named_mirror.properties().length";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004502 CHECK_EQ(3, CompileRun(source)->Int32Value(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004503
4504 source = "indexed_mirror.properties().length";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004505 CHECK_EQ(2, CompileRun(source)->Int32Value(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004506
4507 source = "both_mirror.properties().length";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004508 CHECK_EQ(5, CompileRun(source)->Int32Value(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004509
4510 // Get the interceptor properties for the object with only named interceptor.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004511 CompileRun("var named_values = named_mirror.properties()");
Steve Blocka7e24c12009-10-30 11:49:00 +00004512
4513 // Check that the properties are interceptor properties.
4514 for (int i = 0; i < 3; i++) {
4515 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004516 SNPrintF(buffer,
4517 "named_values[%d] instanceof debug.PropertyMirror", i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004518 CHECK(CompileRun(buffer.start())->BooleanValue(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004519
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004520 SNPrintF(buffer, "named_values[%d].isNative()", i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004521 CHECK(CompileRun(buffer.start())->BooleanValue(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004522 }
4523
4524 // Get the interceptor properties for the object with only indexed
4525 // interceptor.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004526 CompileRun("var indexed_values = indexed_mirror.properties()");
Steve Blocka7e24c12009-10-30 11:49:00 +00004527
4528 // Check that the properties are interceptor properties.
4529 for (int i = 0; i < 2; i++) {
4530 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004531 SNPrintF(buffer,
4532 "indexed_values[%d] instanceof debug.PropertyMirror", i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004533 CHECK(CompileRun(buffer.start())->BooleanValue(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004534 }
4535
4536 // Get the interceptor properties for the object with both types of
4537 // interceptors.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004538 CompileRun("var both_values = both_mirror.properties()");
Steve Blocka7e24c12009-10-30 11:49:00 +00004539
4540 // Check that the properties are interceptor properties.
4541 for (int i = 0; i < 5; i++) {
4542 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004543 SNPrintF(buffer, "both_values[%d] instanceof debug.PropertyMirror", i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004544 CHECK(CompileRun(buffer.start())->BooleanValue(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004545 }
4546
4547 // Check the property names.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004548 source = "both_values[0].name() == '1'";
4549 CHECK(CompileRun(source)->BooleanValue(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004550
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004551 source = "both_values[1].name() == '10'";
4552 CHECK(CompileRun(source)->BooleanValue(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004553
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004554 source = "both_values[2].name() == 'a'";
4555 CHECK(CompileRun(source)->BooleanValue(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004556
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004557 source = "both_values[3].name() == 'b'";
4558 CHECK(CompileRun(source)->BooleanValue(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004559
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004560 source = "both_values[4].name() == 'c'";
4561 CHECK(CompileRun(source)->BooleanValue(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004562}
4563
4564
4565TEST(HiddenPrototypePropertyMirror) {
4566 // Create a V8 environment with debug access.
Steve Blocka7e24c12009-10-30 11:49:00 +00004567 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004568 v8::Isolate* isolate = env->GetIsolate();
4569 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004570 env.ExposeDebug();
4571
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004572 v8::Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
4573 t0->InstanceTemplate()->Set(v8_str(isolate, "x"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004574 v8::Number::New(isolate, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004575 v8::Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004576 t1->SetHiddenPrototype(true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004577 t1->InstanceTemplate()->Set(v8_str(isolate, "y"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004578 v8::Number::New(isolate, 1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004579 v8::Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004580 t2->SetHiddenPrototype(true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004581 t2->InstanceTemplate()->Set(v8_str(isolate, "z"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004582 v8::Number::New(isolate, 2));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004583 v8::Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
4584 t3->InstanceTemplate()->Set(v8_str(isolate, "u"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004585 v8::Number::New(isolate, 3));
Steve Blocka7e24c12009-10-30 11:49:00 +00004586
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004587 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00004588 // Create object and set them on the global object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004589 v8::Local<v8::Object> o0 = t0->GetFunction(context)
4590 .ToLocalChecked()
4591 ->NewInstance(context)
4592 .ToLocalChecked();
4593 CHECK(env->Global()->Set(context, v8_str(isolate, "o0"), o0).FromJust());
4594 v8::Local<v8::Object> o1 = t1->GetFunction(context)
4595 .ToLocalChecked()
4596 ->NewInstance(context)
4597 .ToLocalChecked();
4598 CHECK(env->Global()->Set(context, v8_str(isolate, "o1"), o1).FromJust());
4599 v8::Local<v8::Object> o2 = t2->GetFunction(context)
4600 .ToLocalChecked()
4601 ->NewInstance(context)
4602 .ToLocalChecked();
4603 CHECK(env->Global()->Set(context, v8_str(isolate, "o2"), o2).FromJust());
4604 v8::Local<v8::Object> o3 = t3->GetFunction(context)
4605 .ToLocalChecked()
4606 ->NewInstance(context)
4607 .ToLocalChecked();
4608 CHECK(env->Global()->Set(context, v8_str(isolate, "o3"), o3).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004609
4610 // Get mirrors for the four objects.
4611 CompileRun(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004612 "var o0_mirror = debug.MakeMirror(o0);"
4613 "var o1_mirror = debug.MakeMirror(o1);"
4614 "var o2_mirror = debug.MakeMirror(o2);"
4615 "var o3_mirror = debug.MakeMirror(o3)");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004616 CHECK(CompileRun("o0_mirror instanceof debug.ObjectMirror")
4617 ->BooleanValue(context)
4618 .FromJust());
4619 CHECK(CompileRun("o1_mirror instanceof debug.ObjectMirror")
4620 ->BooleanValue(context)
4621 .FromJust());
4622 CHECK(CompileRun("o2_mirror instanceof debug.ObjectMirror")
4623 ->BooleanValue(context)
4624 .FromJust());
4625 CHECK(CompileRun("o3_mirror instanceof debug.ObjectMirror")
4626 ->BooleanValue(context)
4627 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004628
4629 // Check that each object has one property.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004630 CHECK_EQ(1, CompileRun("o0_mirror.propertyNames().length")
4631 ->Int32Value(context)
4632 .FromJust());
4633 CHECK_EQ(1, CompileRun("o1_mirror.propertyNames().length")
4634 ->Int32Value(context)
4635 .FromJust());
4636 CHECK_EQ(1, CompileRun("o2_mirror.propertyNames().length")
4637 ->Int32Value(context)
4638 .FromJust());
4639 CHECK_EQ(1, CompileRun("o3_mirror.propertyNames().length")
4640 ->Int32Value(context)
4641 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004642
4643 // Set o1 as prototype for o0. o1 has the hidden prototype flag so all
4644 // properties on o1 should be seen on o0.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004645 CHECK(o0->Set(context, v8_str(isolate, "__proto__"), o1).FromJust());
4646 CHECK_EQ(2, CompileRun("o0_mirror.propertyNames().length")
4647 ->Int32Value(context)
4648 .FromJust());
4649 CHECK_EQ(0, CompileRun("o0_mirror.property('x').value().value()")
4650 ->Int32Value(context)
4651 .FromJust());
4652 CHECK_EQ(1, CompileRun("o0_mirror.property('y').value().value()")
4653 ->Int32Value(context)
4654 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004655
4656 // Set o2 as prototype for o0 (it will end up after o1 as o1 has the hidden
4657 // prototype flag. o2 also has the hidden prototype flag so all properties
4658 // on o2 should be seen on o0 as well as properties on o1.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004659 CHECK(o0->Set(context, v8_str(isolate, "__proto__"), o2).FromJust());
4660 CHECK_EQ(3, CompileRun("o0_mirror.propertyNames().length")
4661 ->Int32Value(context)
4662 .FromJust());
4663 CHECK_EQ(0, CompileRun("o0_mirror.property('x').value().value()")
4664 ->Int32Value(context)
4665 .FromJust());
4666 CHECK_EQ(1, CompileRun("o0_mirror.property('y').value().value()")
4667 ->Int32Value(context)
4668 .FromJust());
4669 CHECK_EQ(2, CompileRun("o0_mirror.property('z').value().value()")
4670 ->Int32Value(context)
4671 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004672
4673 // Set o3 as prototype for o0 (it will end up after o1 and o2 as both o1 and
4674 // o2 has the hidden prototype flag. o3 does not have the hidden prototype
4675 // flag so properties on o3 should not be seen on o0 whereas the properties
4676 // from o1 and o2 should still be seen on o0.
4677 // Final prototype chain: o0 -> o1 -> o2 -> o3
4678 // Hidden prototypes: ^^ ^^
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004679 CHECK(o0->Set(context, v8_str(isolate, "__proto__"), o3).FromJust());
4680 CHECK_EQ(3, CompileRun("o0_mirror.propertyNames().length")
4681 ->Int32Value(context)
4682 .FromJust());
4683 CHECK_EQ(1, CompileRun("o3_mirror.propertyNames().length")
4684 ->Int32Value(context)
4685 .FromJust());
4686 CHECK_EQ(0, CompileRun("o0_mirror.property('x').value().value()")
4687 ->Int32Value(context)
4688 .FromJust());
4689 CHECK_EQ(1, CompileRun("o0_mirror.property('y').value().value()")
4690 ->Int32Value(context)
4691 .FromJust());
4692 CHECK_EQ(2, CompileRun("o0_mirror.property('z').value().value()")
4693 ->Int32Value(context)
4694 .FromJust());
4695 CHECK(CompileRun("o0_mirror.property('u').isUndefined()")
4696 ->BooleanValue(context)
4697 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004698
4699 // The prototype (__proto__) for o0 should be o3 as o1 and o2 are hidden.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004700 CHECK(CompileRun("o0_mirror.protoObject() == o3_mirror")
4701 ->BooleanValue(context)
4702 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004703}
4704
4705
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004706static void ProtperyXNativeGetter(
4707 v8::Local<v8::String> property,
4708 const v8::PropertyCallbackInfo<v8::Value>& info) {
4709 info.GetReturnValue().Set(10);
Steve Blocka7e24c12009-10-30 11:49:00 +00004710}
4711
4712
4713TEST(NativeGetterPropertyMirror) {
4714 // Create a V8 environment with debug access.
Steve Blocka7e24c12009-10-30 11:49:00 +00004715 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004716 v8::Isolate* isolate = env->GetIsolate();
4717 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004718 env.ExposeDebug();
4719
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004720 v8::Local<v8::Context> context = env.context();
4721 v8::Local<v8::String> name = v8_str(isolate, "x");
Steve Blocka7e24c12009-10-30 11:49:00 +00004722 // Create object with named accessor.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004723 v8::Local<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
4724 named->SetAccessor(name, &ProtperyXNativeGetter, NULL, v8::Local<v8::Value>(),
4725 v8::DEFAULT, v8::None);
Steve Blocka7e24c12009-10-30 11:49:00 +00004726
4727 // Create object with named property getter.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004728 CHECK(env->Global()
4729 ->Set(context, v8_str(isolate, "instance"),
4730 named->NewInstance(context).ToLocalChecked())
4731 .FromJust());
4732 CHECK_EQ(10, CompileRun("instance.x")->Int32Value(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004733
4734 // Get mirror for the object with property getter.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004735 CompileRun("var instance_mirror = debug.MakeMirror(instance);");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004736 CHECK(CompileRun("instance_mirror instanceof debug.ObjectMirror")
4737 ->BooleanValue(context)
4738 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004739
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004740 CompileRun("var named_names = instance_mirror.propertyNames();");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004741 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value(context).FromJust());
4742 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue(context).FromJust());
4743 CHECK(CompileRun("instance_mirror.property('x').value().isNumber()")
4744 ->BooleanValue(context)
4745 .FromJust());
4746 CHECK(CompileRun("instance_mirror.property('x').value().value() == 10")
4747 ->BooleanValue(context)
4748 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004749}
4750
4751
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004752static void ProtperyXNativeGetterThrowingError(
4753 v8::Local<v8::String> property,
4754 const v8::PropertyCallbackInfo<v8::Value>& info) {
4755 CompileRun("throw new Error('Error message');");
Steve Blocka7e24c12009-10-30 11:49:00 +00004756}
4757
4758
4759TEST(NativeGetterThrowingErrorPropertyMirror) {
4760 // Create a V8 environment with debug access.
Steve Blocka7e24c12009-10-30 11:49:00 +00004761 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004762 v8::Isolate* isolate = env->GetIsolate();
4763 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004764 env.ExposeDebug();
4765
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004766 v8::Local<v8::Context> context = env.context();
4767 v8::Local<v8::String> name = v8_str(isolate, "x");
Steve Blocka7e24c12009-10-30 11:49:00 +00004768 // Create object with named accessor.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004769 v8::Local<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004770 named->SetAccessor(name, &ProtperyXNativeGetterThrowingError, NULL,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004771 v8::Local<v8::Value>(), v8::DEFAULT, v8::None);
Steve Blocka7e24c12009-10-30 11:49:00 +00004772
4773 // Create object with named property getter.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004774 CHECK(env->Global()
4775 ->Set(context, v8_str(isolate, "instance"),
4776 named->NewInstance(context).ToLocalChecked())
4777 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004778
4779 // Get mirror for the object with property getter.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004780 CompileRun("var instance_mirror = debug.MakeMirror(instance);");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004781 CHECK(CompileRun("instance_mirror instanceof debug.ObjectMirror")
4782 ->BooleanValue(context)
4783 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004784 CompileRun("named_names = instance_mirror.propertyNames();");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004785 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value(context).FromJust());
4786 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue(context).FromJust());
4787 CHECK(CompileRun("instance_mirror.property('x').value().isError()")
4788 ->BooleanValue(context)
4789 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004790
4791 // Check that the message is that passed to the Error constructor.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004792 CHECK(
4793 CompileRun(
4794 "instance_mirror.property('x').value().message() == 'Error message'")
4795 ->BooleanValue(context)
4796 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00004797}
4798
4799
Steve Blockd0582a62009-12-15 09:54:21 +00004800// Test that hidden properties object is not returned as an unnamed property
4801// among regular properties.
4802// See http://crbug.com/26491
4803TEST(NoHiddenProperties) {
4804 // Create a V8 environment with debug access.
Steve Blockd0582a62009-12-15 09:54:21 +00004805 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004806 v8::Isolate* isolate = env->GetIsolate();
4807 v8::HandleScope scope(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +00004808 env.ExposeDebug();
4809
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004810 v8::Local<v8::Context> context = env.context();
Steve Blockd0582a62009-12-15 09:54:21 +00004811 // Create an object in the global scope.
4812 const char* source = "var obj = {a: 1};";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004813 v8::Script::Compile(context, v8_str(isolate, source))
4814 .ToLocalChecked()
4815 ->Run(context)
4816 .ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00004817 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004818 env->Global()->Get(context, v8_str(isolate, "obj")).ToLocalChecked());
Steve Blockd0582a62009-12-15 09:54:21 +00004819 // Set a hidden property on the object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004820 obj->SetPrivate(
4821 env.context(),
4822 v8::Private::New(isolate, v8_str(isolate, "v8::test-debug::a")),
4823 v8::Int32::New(isolate, 11))
4824 .FromJust();
Steve Blockd0582a62009-12-15 09:54:21 +00004825
4826 // Get mirror for the object with property getter.
4827 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004828 CHECK(CompileRun("obj_mirror instanceof debug.ObjectMirror")
4829 ->BooleanValue(context)
4830 .FromJust());
Steve Blockd0582a62009-12-15 09:54:21 +00004831 CompileRun("var named_names = obj_mirror.propertyNames();");
4832 // There should be exactly one property. But there is also an unnamed
4833 // property whose value is hidden properties dictionary. The latter
4834 // property should not be in the list of reguar properties.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004835 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value(context).FromJust());
4836 CHECK(CompileRun("named_names[0] == 'a'")->BooleanValue(context).FromJust());
4837 CHECK(CompileRun("obj_mirror.property('a').value().value() == 1")
4838 ->BooleanValue(context)
4839 .FromJust());
Steve Blockd0582a62009-12-15 09:54:21 +00004840
4841 // Object created by t0 will become hidden prototype of object 'obj'.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004842 v8::Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
4843 t0->InstanceTemplate()->Set(v8_str(isolate, "b"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004844 v8::Number::New(isolate, 2));
Steve Blockd0582a62009-12-15 09:54:21 +00004845 t0->SetHiddenPrototype(true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004846 v8::Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
4847 t1->InstanceTemplate()->Set(v8_str(isolate, "c"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004848 v8::Number::New(isolate, 3));
Steve Blockd0582a62009-12-15 09:54:21 +00004849
4850 // Create proto objects, add hidden properties to them and set them on
4851 // the global object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004852 v8::Local<v8::Object> protoObj = t0->GetFunction(context)
4853 .ToLocalChecked()
4854 ->NewInstance(context)
4855 .ToLocalChecked();
4856 protoObj->SetPrivate(
4857 env.context(),
4858 v8::Private::New(isolate, v8_str(isolate, "v8::test-debug::b")),
4859 v8::Int32::New(isolate, 12))
4860 .FromJust();
4861 CHECK(env->Global()
4862 ->Set(context, v8_str(isolate, "protoObj"), protoObj)
4863 .FromJust());
4864 v8::Local<v8::Object> grandProtoObj = t1->GetFunction(context)
4865 .ToLocalChecked()
4866 ->NewInstance(context)
4867 .ToLocalChecked();
4868 grandProtoObj->SetPrivate(env.context(),
4869 v8::Private::New(
4870 isolate, v8_str(isolate, "v8::test-debug::c")),
4871 v8::Int32::New(isolate, 13))
4872 .FromJust();
4873 CHECK(env->Global()
4874 ->Set(context, v8_str(isolate, "grandProtoObj"), grandProtoObj)
4875 .FromJust());
Steve Blockd0582a62009-12-15 09:54:21 +00004876
4877 // Setting prototypes: obj->protoObj->grandProtoObj
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004878 CHECK(protoObj->Set(context, v8_str(isolate, "__proto__"), grandProtoObj)
4879 .FromJust());
4880 CHECK(obj->Set(context, v8_str(isolate, "__proto__"), protoObj).FromJust());
Steve Blockd0582a62009-12-15 09:54:21 +00004881
4882 // Get mirror for the object with property getter.
4883 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004884 CHECK(CompileRun("obj_mirror instanceof debug.ObjectMirror")
4885 ->BooleanValue(context)
4886 .FromJust());
Steve Blockd0582a62009-12-15 09:54:21 +00004887 CompileRun("var named_names = obj_mirror.propertyNames();");
4888 // There should be exactly two properties - one from the object itself and
4889 // another from its hidden prototype.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004890 CHECK_EQ(2, CompileRun("named_names.length")->Int32Value(context).FromJust());
Steve Blockd0582a62009-12-15 09:54:21 +00004891 CHECK(CompileRun("named_names.sort(); named_names[0] == 'a' &&"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004892 "named_names[1] == 'b'")
4893 ->BooleanValue(context)
4894 .FromJust());
4895 CHECK(CompileRun("obj_mirror.property('a').value().value() == 1")
4896 ->BooleanValue(context)
4897 .FromJust());
4898 CHECK(CompileRun("obj_mirror.property('b').value().value() == 2")
4899 ->BooleanValue(context)
4900 .FromJust());
Steve Blockd0582a62009-12-15 09:54:21 +00004901}
4902
Steve Blocka7e24c12009-10-30 11:49:00 +00004903
4904// Multithreaded tests of JSON debugger protocol
4905
4906// Support classes
4907
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004908// Provides synchronization between N threads, where N is a template parameter.
4909// The Wait() call blocks a thread until it is called for the Nth time, then all
4910// calls return. Each ThreadBarrier object can only be used once.
4911template <int N>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004912class ThreadBarrier final {
Steve Blocka7e24c12009-10-30 11:49:00 +00004913 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004914 ThreadBarrier() : num_blocked_(0) {}
4915
4916 ~ThreadBarrier() {
4917 LockGuard<Mutex> lock_guard(&mutex_);
4918 if (num_blocked_ != 0) {
4919 CHECK_EQ(N, num_blocked_);
4920 }
4921 }
4922
4923 void Wait() {
4924 LockGuard<Mutex> lock_guard(&mutex_);
4925 CHECK_LT(num_blocked_, N);
4926 num_blocked_++;
4927 if (N == num_blocked_) {
4928 // Signal and unblock all waiting threads.
4929 cv_.NotifyAll();
4930 printf("BARRIER\n\n");
4931 fflush(stdout);
4932 } else { // Wait for the semaphore.
4933 while (num_blocked_ < N) {
4934 cv_.Wait(&mutex_);
4935 }
4936 }
4937 CHECK_EQ(N, num_blocked_);
4938 }
4939
Steve Blocka7e24c12009-10-30 11:49:00 +00004940 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004941 ConditionVariable cv_;
4942 Mutex mutex_;
Steve Blocka7e24c12009-10-30 11:49:00 +00004943 int num_blocked_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004944
4945 STATIC_ASSERT(N > 0);
4946
4947 DISALLOW_COPY_AND_ASSIGN(ThreadBarrier);
Steve Blocka7e24c12009-10-30 11:49:00 +00004948};
4949
Steve Blocka7e24c12009-10-30 11:49:00 +00004950
4951// A set containing enough barriers and semaphores for any of the tests.
4952class Barriers {
4953 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004954 Barriers() : semaphore_1(0), semaphore_2(0) {}
4955 ThreadBarrier<2> barrier_1;
4956 ThreadBarrier<2> barrier_2;
4957 ThreadBarrier<2> barrier_3;
4958 ThreadBarrier<2> barrier_4;
4959 ThreadBarrier<2> barrier_5;
4960 v8::base::Semaphore semaphore_1;
4961 v8::base::Semaphore semaphore_2;
Steve Blocka7e24c12009-10-30 11:49:00 +00004962};
4963
Steve Blocka7e24c12009-10-30 11:49:00 +00004964
4965// We match parts of the message to decide if it is a break message.
4966bool IsBreakEventMessage(char *message) {
4967 const char* type_event = "\"type\":\"event\"";
4968 const char* event_break = "\"event\":\"break\"";
4969 // Does the message contain both type:event and event:break?
4970 return strstr(message, type_event) != NULL &&
4971 strstr(message, event_break) != NULL;
4972}
4973
4974
Steve Block3ce2e202009-11-05 08:53:23 +00004975// We match parts of the message to decide if it is a exception message.
4976bool IsExceptionEventMessage(char *message) {
4977 const char* type_event = "\"type\":\"event\"";
4978 const char* event_exception = "\"event\":\"exception\"";
4979 // Does the message contain both type:event and event:exception?
4980 return strstr(message, type_event) != NULL &&
4981 strstr(message, event_exception) != NULL;
4982}
4983
4984
4985// We match the message wether it is an evaluate response message.
4986bool IsEvaluateResponseMessage(char* message) {
4987 const char* type_response = "\"type\":\"response\"";
4988 const char* command_evaluate = "\"command\":\"evaluate\"";
4989 // Does the message contain both type:response and command:evaluate?
4990 return strstr(message, type_response) != NULL &&
4991 strstr(message, command_evaluate) != NULL;
4992}
4993
4994
Andrei Popescu402d9372010-02-26 13:31:12 +00004995static int StringToInt(const char* s) {
4996 return atoi(s); // NOLINT
4997}
4998
4999
Steve Block3ce2e202009-11-05 08:53:23 +00005000// We match parts of the message to get evaluate result int value.
5001int GetEvaluateIntResult(char *message) {
5002 const char* value = "\"value\":";
5003 char* pos = strstr(message, value);
5004 if (pos == NULL) {
5005 return -1;
5006 }
5007 int res = -1;
Andrei Popescu402d9372010-02-26 13:31:12 +00005008 res = StringToInt(pos + strlen(value));
Steve Block3ce2e202009-11-05 08:53:23 +00005009 return res;
5010}
5011
5012
5013// We match parts of the message to get hit breakpoint id.
5014int GetBreakpointIdFromBreakEventMessage(char *message) {
5015 const char* breakpoints = "\"breakpoints\":[";
5016 char* pos = strstr(message, breakpoints);
5017 if (pos == NULL) {
5018 return -1;
5019 }
5020 int res = -1;
Andrei Popescu402d9372010-02-26 13:31:12 +00005021 res = StringToInt(pos + strlen(breakpoints));
Steve Block3ce2e202009-11-05 08:53:23 +00005022 return res;
5023}
5024
5025
Leon Clarked91b9f72010-01-27 17:25:45 +00005026// We match parts of the message to get total frames number.
5027int GetTotalFramesInt(char *message) {
5028 const char* prefix = "\"totalFrames\":";
5029 char* pos = strstr(message, prefix);
5030 if (pos == NULL) {
5031 return -1;
5032 }
5033 pos += strlen(prefix);
Andrei Popescu402d9372010-02-26 13:31:12 +00005034 int res = StringToInt(pos);
Leon Clarked91b9f72010-01-27 17:25:45 +00005035 return res;
5036}
5037
5038
Iain Merrick9ac36c92010-09-13 15:29:50 +01005039// We match parts of the message to get source line.
5040int GetSourceLineFromBreakEventMessage(char *message) {
5041 const char* source_line = "\"sourceLine\":";
5042 char* pos = strstr(message, source_line);
5043 if (pos == NULL) {
5044 return -1;
5045 }
5046 int res = -1;
5047 res = StringToInt(pos + strlen(source_line));
5048 return res;
5049}
5050
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005051
Steve Blocka7e24c12009-10-30 11:49:00 +00005052/* Test MessageQueues */
5053/* Tests the message queues that hold debugger commands and
5054 * response messages to the debugger. Fills queues and makes
5055 * them grow.
5056 */
5057Barriers message_queue_barriers;
5058
5059// This is the debugger thread, that executes no v8 calls except
5060// placing JSON debugger commands in the queue.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005061class MessageQueueDebuggerThread : public v8::base::Thread {
Steve Blocka7e24c12009-10-30 11:49:00 +00005062 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005063 MessageQueueDebuggerThread()
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005064 : Thread(Options("MessageQueueDebuggerThread")) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00005065 void Run();
5066};
5067
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005068
5069static void MessageHandler(const v8::Debug::Message& message) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005070 v8::Local<v8::String> json = message.GetJSON();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005071 v8::String::Utf8Value utf8(json);
5072 if (IsBreakEventMessage(*utf8)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005073 // Lets test script wait until break occurs to send commands.
5074 // Signals when a break is reported.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005075 message_queue_barriers.semaphore_2.Signal();
Steve Blocka7e24c12009-10-30 11:49:00 +00005076 }
5077
5078 // Allow message handler to block on a semaphore, to test queueing of
5079 // messages while blocked.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005080 message_queue_barriers.semaphore_1.Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +00005081}
5082
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005083
Steve Blocka7e24c12009-10-30 11:49:00 +00005084void MessageQueueDebuggerThread::Run() {
5085 const int kBufferSize = 1000;
5086 uint16_t buffer_1[kBufferSize];
5087 uint16_t buffer_2[kBufferSize];
5088 const char* command_1 =
5089 "{\"seq\":117,"
5090 "\"type\":\"request\","
5091 "\"command\":\"evaluate\","
5092 "\"arguments\":{\"expression\":\"1+2\"}}";
5093 const char* command_2 =
5094 "{\"seq\":118,"
5095 "\"type\":\"request\","
5096 "\"command\":\"evaluate\","
5097 "\"arguments\":{\"expression\":\"1+a\"}}";
5098 const char* command_3 =
5099 "{\"seq\":119,"
5100 "\"type\":\"request\","
5101 "\"command\":\"evaluate\","
5102 "\"arguments\":{\"expression\":\"c.d * b\"}}";
5103 const char* command_continue =
5104 "{\"seq\":106,"
5105 "\"type\":\"request\","
5106 "\"command\":\"continue\"}";
5107 const char* command_single_step =
5108 "{\"seq\":107,"
5109 "\"type\":\"request\","
5110 "\"command\":\"continue\","
5111 "\"arguments\":{\"stepaction\":\"next\"}}";
5112
5113 /* Interleaved sequence of actions by the two threads:*/
5114 // Main thread compiles and runs source_1
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005115 message_queue_barriers.semaphore_1.Signal();
Steve Blocka7e24c12009-10-30 11:49:00 +00005116 message_queue_barriers.barrier_1.Wait();
5117 // Post 6 commands, filling the command queue and making it expand.
5118 // These calls return immediately, but the commands stay on the queue
5119 // until the execution of source_2.
5120 // Note: AsciiToUtf16 executes before SendCommand, so command is copied
5121 // to buffer before buffer is sent to SendCommand.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005122 v8::Isolate* isolate = CcTest::isolate();
5123 v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_1, buffer_1));
5124 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_2, buffer_2));
5125 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
5126 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
5127 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00005128 message_queue_barriers.barrier_2.Wait();
5129 // Main thread compiles and runs source_2.
5130 // Queued commands are executed at the start of compilation of source_2(
5131 // beforeCompile event).
5132 // Free the message handler to process all the messages from the queue. 7
5133 // messages are expected: 2 afterCompile events and 5 responses.
5134 // All the commands added so far will fail to execute as long as call stack
5135 // is empty on beforeCompile event.
5136 for (int i = 0; i < 6 ; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005137 message_queue_barriers.semaphore_1.Signal();
Steve Blocka7e24c12009-10-30 11:49:00 +00005138 }
5139 message_queue_barriers.barrier_3.Wait();
5140 // Main thread compiles and runs source_3.
5141 // Don't stop in the afterCompile handler.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005142 message_queue_barriers.semaphore_1.Signal();
Steve Blocka7e24c12009-10-30 11:49:00 +00005143 // source_3 includes a debugger statement, which causes a break event.
5144 // Wait on break event from hitting "debugger" statement
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005145 message_queue_barriers.semaphore_2.Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +00005146 // These should execute after the "debugger" statement in source_2
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005147 v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_1, buffer_1));
5148 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_2, buffer_2));
5149 v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
5150 v8::Debug::SendCommand(
5151 isolate, buffer_2, AsciiToUtf16(command_single_step, buffer_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00005152 // Run after 2 break events, 4 responses.
5153 for (int i = 0; i < 6 ; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005154 message_queue_barriers.semaphore_1.Signal();
Steve Blocka7e24c12009-10-30 11:49:00 +00005155 }
5156 // Wait on break event after a single step executes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005157 message_queue_barriers.semaphore_2.Wait();
5158 v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_2, buffer_1));
5159 v8::Debug::SendCommand(
5160 isolate, buffer_2, AsciiToUtf16(command_continue, buffer_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00005161 // Run after 2 responses.
5162 for (int i = 0; i < 2 ; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005163 message_queue_barriers.semaphore_1.Signal();
Steve Blocka7e24c12009-10-30 11:49:00 +00005164 }
5165 // Main thread continues running source_3 to end, waits for this thread.
5166}
5167
Steve Blocka7e24c12009-10-30 11:49:00 +00005168
5169// This thread runs the v8 engine.
5170TEST(MessageQueues) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005171 MessageQueueDebuggerThread message_queue_debugger_thread;
Steve Block44f0eee2011-05-26 01:26:41 +01005172
Steve Blocka7e24c12009-10-30 11:49:00 +00005173 // Create a V8 environment
Steve Blocka7e24c12009-10-30 11:49:00 +00005174 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005175 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005176 v8::Debug::SetMessageHandler(env->GetIsolate(), MessageHandler);
Steve Blocka7e24c12009-10-30 11:49:00 +00005177 message_queue_debugger_thread.Start();
5178
5179 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
5180 const char* source_2 = "e = 17;";
5181 const char* source_3 = "a = 4; debugger; a = 5; a = 6; a = 7;";
5182
5183 // See MessageQueueDebuggerThread::Run for interleaved sequence of
5184 // API calls and events in the two threads.
5185 CompileRun(source_1);
5186 message_queue_barriers.barrier_1.Wait();
5187 message_queue_barriers.barrier_2.Wait();
5188 CompileRun(source_2);
5189 message_queue_barriers.barrier_3.Wait();
5190 CompileRun(source_3);
5191 message_queue_debugger_thread.Join();
5192 fflush(stdout);
5193}
5194
5195
5196class TestClientData : public v8::Debug::ClientData {
5197 public:
5198 TestClientData() {
5199 constructor_call_counter++;
5200 }
5201 virtual ~TestClientData() {
5202 destructor_call_counter++;
5203 }
5204
5205 static void ResetCounters() {
5206 constructor_call_counter = 0;
5207 destructor_call_counter = 0;
5208 }
5209
5210 static int constructor_call_counter;
5211 static int destructor_call_counter;
5212};
5213
5214int TestClientData::constructor_call_counter = 0;
5215int TestClientData::destructor_call_counter = 0;
5216
5217
5218// Tests that MessageQueue doesn't destroy client data when expands and
5219// does destroy when it dies.
5220TEST(MessageQueueExpandAndDestroy) {
5221 TestClientData::ResetCounters();
5222 { // Create a scope for the queue.
5223 CommandMessageQueue queue(1);
5224 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5225 new TestClientData()));
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 CHECK_EQ(0, TestClientData::destructor_call_counter);
5231 queue.Get().Dispose();
5232 CHECK_EQ(1, TestClientData::destructor_call_counter);
5233 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5234 new TestClientData()));
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 CHECK_EQ(1, TestClientData::destructor_call_counter);
5244 queue.Get().Dispose();
5245 CHECK_EQ(2, TestClientData::destructor_call_counter);
5246 }
5247 // All the client data should be destroyed when the queue is destroyed.
5248 CHECK_EQ(TestClientData::destructor_call_counter,
5249 TestClientData::destructor_call_counter);
5250}
5251
5252
5253static int handled_client_data_instances_count = 0;
5254static void MessageHandlerCountingClientData(
5255 const v8::Debug::Message& message) {
5256 if (message.GetClientData() != NULL) {
5257 handled_client_data_instances_count++;
5258 }
5259}
5260
5261
5262// Tests that all client data passed to the debugger are sent to the handler.
5263TEST(SendClientDataToHandler) {
5264 // Create a V8 environment
Steve Blocka7e24c12009-10-30 11:49:00 +00005265 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005266 v8::Isolate* isolate = env->GetIsolate();
5267 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005268 TestClientData::ResetCounters();
5269 handled_client_data_instances_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005270 v8::Debug::SetMessageHandler(isolate, MessageHandlerCountingClientData);
Steve Blocka7e24c12009-10-30 11:49:00 +00005271 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
5272 const int kBufferSize = 1000;
5273 uint16_t buffer[kBufferSize];
5274 const char* command_1 =
5275 "{\"seq\":117,"
5276 "\"type\":\"request\","
5277 "\"command\":\"evaluate\","
5278 "\"arguments\":{\"expression\":\"1+2\"}}";
5279 const char* command_2 =
5280 "{\"seq\":118,"
5281 "\"type\":\"request\","
5282 "\"command\":\"evaluate\","
5283 "\"arguments\":{\"expression\":\"1+a\"}}";
5284 const char* command_continue =
5285 "{\"seq\":106,"
5286 "\"type\":\"request\","
5287 "\"command\":\"continue\"}";
5288
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005289 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_1, buffer),
Steve Blocka7e24c12009-10-30 11:49:00 +00005290 new TestClientData());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005291 v8::Debug::SendCommand(
5292 isolate, buffer, AsciiToUtf16(command_2, buffer), NULL);
5293 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_2, buffer),
Steve Blocka7e24c12009-10-30 11:49:00 +00005294 new TestClientData());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005295 v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_2, buffer),
Steve Blocka7e24c12009-10-30 11:49:00 +00005296 new TestClientData());
5297 // All the messages will be processed on beforeCompile event.
5298 CompileRun(source_1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005299 v8::Debug::SendCommand(
5300 isolate, buffer, AsciiToUtf16(command_continue, buffer));
Steve Blocka7e24c12009-10-30 11:49:00 +00005301 CHECK_EQ(3, TestClientData::constructor_call_counter);
5302 CHECK_EQ(TestClientData::constructor_call_counter,
5303 handled_client_data_instances_count);
5304 CHECK_EQ(TestClientData::constructor_call_counter,
5305 TestClientData::destructor_call_counter);
5306}
5307
5308
5309/* Test ThreadedDebugging */
5310/* This test interrupts a running infinite loop that is
5311 * occupying the v8 thread by a break command from the
5312 * debugger thread. It then changes the value of a
5313 * global object, to make the loop terminate.
5314 */
5315
5316Barriers threaded_debugging_barriers;
5317
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005318class V8Thread : public v8::base::Thread {
Steve Blocka7e24c12009-10-30 11:49:00 +00005319 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005320 V8Thread() : Thread(Options("V8Thread")) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00005321 void Run();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005322 v8::Isolate* isolate() { return isolate_; }
5323
5324 private:
5325 v8::Isolate* isolate_;
Steve Blocka7e24c12009-10-30 11:49:00 +00005326};
5327
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005328class DebuggerThread : public v8::base::Thread {
Steve Blocka7e24c12009-10-30 11:49:00 +00005329 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005330 explicit DebuggerThread(v8::Isolate* isolate)
5331 : Thread(Options("DebuggerThread")), isolate_(isolate) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00005332 void Run();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005333
5334 private:
5335 v8::Isolate* isolate_;
Steve Blocka7e24c12009-10-30 11:49:00 +00005336};
5337
5338
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005339static void ThreadedAtBarrier1(
5340 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005341 threaded_debugging_barriers.barrier_1.Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +00005342}
5343
5344
5345static void ThreadedMessageHandler(const v8::Debug::Message& message) {
5346 static char print_buffer[1000];
5347 v8::String::Value json(message.GetJSON());
5348 Utf16ToAscii(*json, json.length(), print_buffer);
5349 if (IsBreakEventMessage(print_buffer)) {
Iain Merrick9ac36c92010-09-13 15:29:50 +01005350 // Check that we are inside the while loop.
5351 int source_line = GetSourceLineFromBreakEventMessage(print_buffer);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005352 CHECK(4 <= source_line && source_line <= 10);
Steve Blocka7e24c12009-10-30 11:49:00 +00005353 threaded_debugging_barriers.barrier_2.Wait();
5354 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005355}
5356
5357
5358void V8Thread::Run() {
5359 const char* source =
5360 "flag = true;\n"
Steve Blocka7e24c12009-10-30 11:49:00 +00005361 "\n"
5362 "function foo() {\n"
5363 " var x = 1;\n"
5364 " while ( flag == true ) {\n"
5365 " if ( x == 1 ) {\n"
5366 " ThreadedAtBarrier1();\n"
5367 " }\n"
5368 " x = x + 1;\n"
5369 " }\n"
5370 "}\n"
5371 "\n"
5372 "foo();\n";
5373
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005374 v8::Isolate::CreateParams create_params;
5375 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
5376 isolate_ = v8::Isolate::New(create_params);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005377 threaded_debugging_barriers.barrier_3.Wait();
5378 {
5379 v8::Isolate::Scope isolate_scope(isolate_);
5380 DebugLocalContext env(isolate_);
5381 v8::HandleScope scope(isolate_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005382 v8::Debug::SetMessageHandler(isolate_, &ThreadedMessageHandler);
5383 v8::Local<v8::ObjectTemplate> global_template =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005384 v8::ObjectTemplate::New(env->GetIsolate());
5385 global_template->Set(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005386 v8_str(env->GetIsolate(), "ThreadedAtBarrier1"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005387 v8::FunctionTemplate::New(isolate_, ThreadedAtBarrier1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005388 v8::Local<v8::Context> context =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005389 v8::Context::New(isolate_, NULL, global_template);
5390 v8::Context::Scope context_scope(context);
Steve Blocka7e24c12009-10-30 11:49:00 +00005391
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005392 CompileRun(source);
5393 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005394 threaded_debugging_barriers.barrier_4.Wait();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005395 isolate_->Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +00005396}
5397
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005398
Steve Blocka7e24c12009-10-30 11:49:00 +00005399void DebuggerThread::Run() {
5400 const int kBufSize = 1000;
5401 uint16_t buffer[kBufSize];
5402
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005403 const char* command_1 =
5404 "{\"seq\":102,"
Steve Blocka7e24c12009-10-30 11:49:00 +00005405 "\"type\":\"request\","
5406 "\"command\":\"evaluate\","
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005407 "\"arguments\":{\"expression\":\"flag = false\"}}";
Steve Blocka7e24c12009-10-30 11:49:00 +00005408 const char* command_2 = "{\"seq\":103,"
5409 "\"type\":\"request\","
5410 "\"command\":\"continue\"}";
5411
5412 threaded_debugging_barriers.barrier_1.Wait();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005413 v8::Debug::DebugBreak(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00005414 threaded_debugging_barriers.barrier_2.Wait();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005415 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_1, buffer));
5416 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_2, buffer));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005417 threaded_debugging_barriers.barrier_4.Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +00005418}
5419
Steve Blocka7e24c12009-10-30 11:49:00 +00005420
5421TEST(ThreadedDebugging) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005422 V8Thread v8_thread;
Steve Block44f0eee2011-05-26 01:26:41 +01005423
Steve Blocka7e24c12009-10-30 11:49:00 +00005424 // Create a V8 environment
Steve Blocka7e24c12009-10-30 11:49:00 +00005425 v8_thread.Start();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005426 threaded_debugging_barriers.barrier_3.Wait();
5427 DebuggerThread debugger_thread(v8_thread.isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005428 debugger_thread.Start();
5429
5430 v8_thread.Join();
5431 debugger_thread.Join();
5432}
5433
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005434
Steve Blocka7e24c12009-10-30 11:49:00 +00005435/* Test RecursiveBreakpoints */
5436/* In this test, the debugger evaluates a function with a breakpoint, after
5437 * hitting a breakpoint in another function. We do this with both values
5438 * of the flag enabling recursive breakpoints, and verify that the second
5439 * breakpoint is hit when enabled, and missed when disabled.
5440 */
5441
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005442class BreakpointsV8Thread : public v8::base::Thread {
Steve Blocka7e24c12009-10-30 11:49:00 +00005443 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005444 BreakpointsV8Thread() : Thread(Options("BreakpointsV8Thread")) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00005445 void Run();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005446
5447 v8::Isolate* isolate() { return isolate_; }
5448
5449 private:
5450 v8::Isolate* isolate_;
Steve Blocka7e24c12009-10-30 11:49:00 +00005451};
5452
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005453class BreakpointsDebuggerThread : public v8::base::Thread {
Steve Blocka7e24c12009-10-30 11:49:00 +00005454 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005455 BreakpointsDebuggerThread(bool global_evaluate, v8::Isolate* isolate)
5456 : Thread(Options("BreakpointsDebuggerThread")),
5457 global_evaluate_(global_evaluate),
5458 isolate_(isolate) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00005459 void Run();
Leon Clarked91b9f72010-01-27 17:25:45 +00005460
5461 private:
5462 bool global_evaluate_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005463 v8::Isolate* isolate_;
Steve Blocka7e24c12009-10-30 11:49:00 +00005464};
5465
5466
5467Barriers* breakpoints_barriers;
Steve Block3ce2e202009-11-05 08:53:23 +00005468int break_event_breakpoint_id;
5469int evaluate_int_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00005470
5471static void BreakpointsMessageHandler(const v8::Debug::Message& message) {
5472 static char print_buffer[1000];
5473 v8::String::Value json(message.GetJSON());
5474 Utf16ToAscii(*json, json.length(), print_buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00005475
Steve Blocka7e24c12009-10-30 11:49:00 +00005476 if (IsBreakEventMessage(print_buffer)) {
Steve Block3ce2e202009-11-05 08:53:23 +00005477 break_event_breakpoint_id =
5478 GetBreakpointIdFromBreakEventMessage(print_buffer);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005479 breakpoints_barriers->semaphore_1.Signal();
Steve Block3ce2e202009-11-05 08:53:23 +00005480 } else if (IsEvaluateResponseMessage(print_buffer)) {
5481 evaluate_int_result = GetEvaluateIntResult(print_buffer);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005482 breakpoints_barriers->semaphore_1.Signal();
Steve Blocka7e24c12009-10-30 11:49:00 +00005483 }
5484}
5485
5486
5487void BreakpointsV8Thread::Run() {
5488 const char* source_1 = "var y_global = 3;\n"
5489 "function cat( new_value ) {\n"
5490 " var x = new_value;\n"
Steve Block3ce2e202009-11-05 08:53:23 +00005491 " y_global = y_global + 4;\n"
Steve Blocka7e24c12009-10-30 11:49:00 +00005492 " x = 3 * x + 1;\n"
Steve Block3ce2e202009-11-05 08:53:23 +00005493 " y_global = y_global + 5;\n"
Steve Blocka7e24c12009-10-30 11:49:00 +00005494 " return x;\n"
5495 "}\n"
5496 "\n"
5497 "function dog() {\n"
5498 " var x = 1;\n"
5499 " x = y_global;"
5500 " var z = 3;"
5501 " x += 100;\n"
5502 " return x;\n"
5503 "}\n"
5504 "\n";
5505 const char* source_2 = "cat(17);\n"
5506 "cat(19);\n";
5507
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005508 v8::Isolate::CreateParams create_params;
5509 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
5510 isolate_ = v8::Isolate::New(create_params);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005511 breakpoints_barriers->barrier_3.Wait();
5512 {
5513 v8::Isolate::Scope isolate_scope(isolate_);
5514 DebugLocalContext env(isolate_);
5515 v8::HandleScope scope(isolate_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005516 v8::Debug::SetMessageHandler(isolate_, &BreakpointsMessageHandler);
Steve Blocka7e24c12009-10-30 11:49:00 +00005517
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005518 CompileRun(source_1);
5519 breakpoints_barriers->barrier_1.Wait();
5520 breakpoints_barriers->barrier_2.Wait();
5521 CompileRun(source_2);
5522 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005523 breakpoints_barriers->barrier_4.Wait();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005524 isolate_->Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +00005525}
5526
5527
5528void BreakpointsDebuggerThread::Run() {
5529 const int kBufSize = 1000;
5530 uint16_t buffer[kBufSize];
5531
5532 const char* command_1 = "{\"seq\":101,"
5533 "\"type\":\"request\","
5534 "\"command\":\"setbreakpoint\","
5535 "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}";
5536 const char* command_2 = "{\"seq\":102,"
5537 "\"type\":\"request\","
5538 "\"command\":\"setbreakpoint\","
5539 "\"arguments\":{\"type\":\"function\",\"target\":\"dog\",\"line\":3}}";
Leon Clarked91b9f72010-01-27 17:25:45 +00005540 const char* command_3;
5541 if (this->global_evaluate_) {
5542 command_3 = "{\"seq\":103,"
5543 "\"type\":\"request\","
5544 "\"command\":\"evaluate\","
5545 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false,"
5546 "\"global\":true}}";
5547 } else {
5548 command_3 = "{\"seq\":103,"
5549 "\"type\":\"request\","
5550 "\"command\":\"evaluate\","
5551 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false}}";
5552 }
5553 const char* command_4;
5554 if (this->global_evaluate_) {
5555 command_4 = "{\"seq\":104,"
5556 "\"type\":\"request\","
5557 "\"command\":\"evaluate\","
5558 "\"arguments\":{\"expression\":\"100 + 8\",\"disable_break\":true,"
5559 "\"global\":true}}";
5560 } else {
5561 command_4 = "{\"seq\":104,"
5562 "\"type\":\"request\","
5563 "\"command\":\"evaluate\","
5564 "\"arguments\":{\"expression\":\"x + 1\",\"disable_break\":true}}";
5565 }
Steve Block3ce2e202009-11-05 08:53:23 +00005566 const char* command_5 = "{\"seq\":105,"
Steve Blocka7e24c12009-10-30 11:49:00 +00005567 "\"type\":\"request\","
5568 "\"command\":\"continue\"}";
Steve Block3ce2e202009-11-05 08:53:23 +00005569 const char* command_6 = "{\"seq\":106,"
Steve Blocka7e24c12009-10-30 11:49:00 +00005570 "\"type\":\"request\","
5571 "\"command\":\"continue\"}";
Leon Clarked91b9f72010-01-27 17:25:45 +00005572 const char* command_7;
5573 if (this->global_evaluate_) {
5574 command_7 = "{\"seq\":107,"
5575 "\"type\":\"request\","
5576 "\"command\":\"evaluate\","
5577 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true,"
5578 "\"global\":true}}";
5579 } else {
5580 command_7 = "{\"seq\":107,"
5581 "\"type\":\"request\","
5582 "\"command\":\"evaluate\","
5583 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true}}";
5584 }
Steve Block3ce2e202009-11-05 08:53:23 +00005585 const char* command_8 = "{\"seq\":108,"
Steve Blocka7e24c12009-10-30 11:49:00 +00005586 "\"type\":\"request\","
5587 "\"command\":\"continue\"}";
5588
5589
5590 // v8 thread initializes, runs source_1
5591 breakpoints_barriers->barrier_1.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005592 // 1:Set breakpoint in cat() (will get id 1).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005593 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_1, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005594 // 2:Set breakpoint in dog() (will get id 2).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005595 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_2, buffer));
Steve Blocka7e24c12009-10-30 11:49:00 +00005596 breakpoints_barriers->barrier_2.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005597 // V8 thread starts compiling source_2.
Steve Blocka7e24c12009-10-30 11:49:00 +00005598 // Automatic break happens, to run queued commands
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005599 // breakpoints_barriers->semaphore_1.Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +00005600 // Commands 1 through 3 run, thread continues.
5601 // v8 thread runs source_2 to breakpoint in cat().
5602 // message callback receives break event.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005603 breakpoints_barriers->semaphore_1.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005604 // Must have hit breakpoint #1.
5605 CHECK_EQ(1, break_event_breakpoint_id);
Steve Blocka7e24c12009-10-30 11:49:00 +00005606 // 4:Evaluate dog() (which has a breakpoint).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005607 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_3, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005608 // V8 thread hits breakpoint in dog().
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005609 breakpoints_barriers->semaphore_1.Wait(); // wait for break event
Steve Block3ce2e202009-11-05 08:53:23 +00005610 // Must have hit breakpoint #2.
5611 CHECK_EQ(2, break_event_breakpoint_id);
5612 // 5:Evaluate (x + 1).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005613 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_4, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005614 // Evaluate (x + 1) finishes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005615 breakpoints_barriers->semaphore_1.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005616 // Must have result 108.
5617 CHECK_EQ(108, evaluate_int_result);
5618 // 6:Continue evaluation of dog().
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005619 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_5, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005620 // Evaluate dog() finishes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005621 breakpoints_barriers->semaphore_1.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005622 // Must have result 107.
5623 CHECK_EQ(107, evaluate_int_result);
Steve Blocka7e24c12009-10-30 11:49:00 +00005624 // 7:Continue evaluation of source_2, finish cat(17), hit breakpoint
5625 // in cat(19).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005626 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_6, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005627 // Message callback gets break event.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005628 breakpoints_barriers->semaphore_1.Wait(); // wait for break event
Steve Block3ce2e202009-11-05 08:53:23 +00005629 // Must have hit breakpoint #1.
5630 CHECK_EQ(1, break_event_breakpoint_id);
5631 // 8: Evaluate dog() with breaks disabled.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005632 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_7, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005633 // Evaluate dog() finishes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005634 breakpoints_barriers->semaphore_1.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005635 // Must have result 116.
5636 CHECK_EQ(116, evaluate_int_result);
Steve Blocka7e24c12009-10-30 11:49:00 +00005637 // 9: Continue evaluation of source2, reach end.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005638 v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_8, buffer));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005639 breakpoints_barriers->barrier_4.Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +00005640}
5641
Leon Clarke888f6722010-01-27 15:57:47 +00005642
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005643void TestRecursiveBreakpointsGeneric(bool global_evaluate) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005644 BreakpointsV8Thread breakpoints_v8_thread;
Leon Clarked91b9f72010-01-27 17:25:45 +00005645
Steve Blocka7e24c12009-10-30 11:49:00 +00005646 // Create a V8 environment
5647 Barriers stack_allocated_breakpoints_barriers;
Steve Blocka7e24c12009-10-30 11:49:00 +00005648 breakpoints_barriers = &stack_allocated_breakpoints_barriers;
5649
5650 breakpoints_v8_thread.Start();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005651 breakpoints_barriers->barrier_3.Wait();
5652 BreakpointsDebuggerThread breakpoints_debugger_thread(
5653 global_evaluate, breakpoints_v8_thread.isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005654 breakpoints_debugger_thread.Start();
5655
5656 breakpoints_v8_thread.Join();
5657 breakpoints_debugger_thread.Join();
5658}
5659
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005660
Leon Clarked91b9f72010-01-27 17:25:45 +00005661TEST(RecursiveBreakpoints) {
5662 TestRecursiveBreakpointsGeneric(false);
5663}
5664
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005665
Leon Clarked91b9f72010-01-27 17:25:45 +00005666TEST(RecursiveBreakpointsGlobal) {
5667 TestRecursiveBreakpointsGeneric(true);
5668}
5669
Steve Blocka7e24c12009-10-30 11:49:00 +00005670
Steve Blocka7e24c12009-10-30 11:49:00 +00005671TEST(SetDebugEventListenerOnUninitializedVM) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005672 v8::Debug::SetDebugEventListener(CcTest::isolate(), DummyDebugEventListener);
Steve Blocka7e24c12009-10-30 11:49:00 +00005673}
5674
5675
5676static void DummyMessageHandler(const v8::Debug::Message& message) {
5677}
5678
5679
5680TEST(SetMessageHandlerOnUninitializedVM) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005681 v8::Debug::SetMessageHandler(CcTest::isolate(), DummyMessageHandler);
Steve Blocka7e24c12009-10-30 11:49:00 +00005682}
5683
5684
5685// Source for a JavaScript function which returns the data parameter of a
5686// function called in the context of the debugger. If no data parameter is
5687// passed it throws an exception.
5688static const char* debugger_call_with_data_source =
5689 "function debugger_call_with_data(exec_state, data) {"
5690 " if (data) return data;"
5691 " throw 'No data!'"
5692 "}";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005693v8::Local<v8::Function> debugger_call_with_data;
Steve Blocka7e24c12009-10-30 11:49:00 +00005694
5695
5696// Source for a JavaScript function which returns the data parameter of a
5697// function called in the context of the debugger. If no data parameter is
5698// passed it throws an exception.
5699static const char* debugger_call_with_closure_source =
5700 "var x = 3;"
5701 "(function (exec_state) {"
5702 " if (exec_state.y) return x - 1;"
5703 " exec_state.y = x;"
5704 " return exec_state.y"
5705 "})";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005706v8::Local<v8::Function> debugger_call_with_closure;
Steve Blocka7e24c12009-10-30 11:49:00 +00005707
5708// Function to retrieve the number of JavaScript frames by calling a JavaScript
5709// in the debugger.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005710static void CheckFrameCount(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005711 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
5712 CHECK(v8::Debug::Call(context, frame_count).ToLocalChecked()->IsNumber());
5713 CHECK_EQ(args[0]->Int32Value(context).FromJust(),
5714 v8::Debug::Call(context, frame_count)
5715 .ToLocalChecked()
5716 ->Int32Value(context)
5717 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00005718}
5719
5720
5721// Function to retrieve the source line of the top JavaScript frame by calling a
5722// JavaScript function in the debugger.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005723static void CheckSourceLine(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005724 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
5725 CHECK(
5726 v8::Debug::Call(context, frame_source_line).ToLocalChecked()->IsNumber());
5727 CHECK_EQ(args[0]->Int32Value(context).FromJust(),
5728 v8::Debug::Call(context, frame_source_line)
5729 .ToLocalChecked()
5730 ->Int32Value(context)
5731 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00005732}
5733
5734
5735// Function to test passing an additional parameter to a JavaScript function
5736// called in the debugger. It also tests that functions called in the debugger
5737// can throw exceptions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005738static void CheckDataParameter(
5739 const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005740 v8::Local<v8::String> data = v8_str(args.GetIsolate(), "Test");
5741 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
5742 CHECK(v8::Debug::Call(context, debugger_call_with_data, data)
5743 .ToLocalChecked()
5744 ->IsString());
Steve Blocka7e24c12009-10-30 11:49:00 +00005745
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005746 for (int i = 0; i < 3; i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005747 v8::TryCatch catcher(args.GetIsolate());
5748 CHECK(v8::Debug::Call(context, debugger_call_with_data).IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005749 CHECK(catcher.HasCaught());
5750 CHECK(catcher.Exception()->IsString());
5751 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005752}
5753
5754
5755// Function to test using a JavaScript with closure in the debugger.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005756static void CheckClosure(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005757 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
5758 CHECK(v8::Debug::Call(context, debugger_call_with_closure)
5759 .ToLocalChecked()
5760 ->IsNumber());
5761 CHECK_EQ(3, v8::Debug::Call(context, debugger_call_with_closure)
5762 .ToLocalChecked()
5763 ->Int32Value(context)
5764 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00005765}
5766
5767
5768// Test functions called through the debugger.
5769TEST(CallFunctionInDebugger) {
5770 // Create and enter a context with the functions CheckFrameCount,
5771 // CheckSourceLine and CheckDataParameter installed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005772 v8::Isolate* isolate = CcTest::isolate();
5773 v8::HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005774 v8::Local<v8::ObjectTemplate> global_template =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005775 v8::ObjectTemplate::New(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005776 global_template->Set(v8_str(isolate, "CheckFrameCount"),
5777 v8::FunctionTemplate::New(isolate, CheckFrameCount));
5778 global_template->Set(v8_str(isolate, "CheckSourceLine"),
5779 v8::FunctionTemplate::New(isolate, CheckSourceLine));
5780 global_template->Set(v8_str(isolate, "CheckDataParameter"),
5781 v8::FunctionTemplate::New(isolate, CheckDataParameter));
5782 global_template->Set(v8_str(isolate, "CheckClosure"),
5783 v8::FunctionTemplate::New(isolate, CheckClosure));
5784 v8::Local<v8::Context> context =
5785 v8::Context::New(isolate, NULL, global_template);
Steve Blocka7e24c12009-10-30 11:49:00 +00005786 v8::Context::Scope context_scope(context);
5787
5788 // Compile a function for checking the number of JavaScript frames.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005789 v8::Script::Compile(context, v8_str(isolate, frame_count_source))
5790 .ToLocalChecked()
5791 ->Run(context)
5792 .ToLocalChecked();
5793 frame_count = v8::Local<v8::Function>::Cast(
5794 context->Global()
5795 ->Get(context, v8_str(isolate, "frame_count"))
5796 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00005797
5798 // Compile a function for returning the source line for the top frame.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005799 v8::Script::Compile(context, v8_str(isolate, frame_source_line_source))
5800 .ToLocalChecked()
5801 ->Run(context)
5802 .ToLocalChecked();
5803 frame_source_line = v8::Local<v8::Function>::Cast(
5804 context->Global()
5805 ->Get(context, v8_str(isolate, "frame_source_line"))
5806 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00005807
5808 // Compile a function returning the data parameter.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005809 v8::Script::Compile(context, v8_str(isolate, debugger_call_with_data_source))
5810 .ToLocalChecked()
5811 ->Run(context)
5812 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005813 debugger_call_with_data = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005814 context->Global()
5815 ->Get(context, v8_str(isolate, "debugger_call_with_data"))
5816 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00005817
5818 // Compile a function capturing closure.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005819 debugger_call_with_closure = v8::Local<v8::Function>::Cast(
5820 v8::Script::Compile(context,
5821 v8_str(isolate, debugger_call_with_closure_source))
5822 .ToLocalChecked()
5823 ->Run(context)
5824 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00005825
Steve Block6ded16b2010-05-10 14:33:55 +01005826 // Calling a function through the debugger returns 0 frames if there are
5827 // no JavaScript frames.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005828 CHECK(v8::Integer::New(isolate, 0)
5829 ->Equals(context,
5830 v8::Debug::Call(context, frame_count).ToLocalChecked())
5831 .FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00005832
5833 // Test that the number of frames can be retrieved.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005834 v8::Script::Compile(context, v8_str(isolate, "CheckFrameCount(1)"))
5835 .ToLocalChecked()
5836 ->Run(context)
5837 .ToLocalChecked();
5838 v8::Script::Compile(context, v8_str(isolate,
5839 "function f() {"
5840 " CheckFrameCount(2);"
5841 "}; f()"))
5842 .ToLocalChecked()
5843 ->Run(context)
5844 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005845
5846 // Test that the source line can be retrieved.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005847 v8::Script::Compile(context, v8_str(isolate, "CheckSourceLine(0)"))
5848 .ToLocalChecked()
5849 ->Run(context)
5850 .ToLocalChecked();
5851 v8::Script::Compile(context, v8_str(isolate,
5852 "function f() {\n"
5853 " CheckSourceLine(1)\n"
5854 " CheckSourceLine(2)\n"
5855 " CheckSourceLine(3)\n"
5856 "}; f()"))
5857 .ToLocalChecked()
5858 ->Run(context)
5859 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005860
5861 // Test that a parameter can be passed to a function called in the debugger.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005862 v8::Script::Compile(context, v8_str(isolate, "CheckDataParameter()"))
5863 .ToLocalChecked()
5864 ->Run(context)
5865 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005866
5867 // Test that a function with closure can be run in the debugger.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005868 v8::Script::Compile(context, v8_str(isolate, "CheckClosure()"))
5869 .ToLocalChecked()
5870 ->Run(context)
5871 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005872
5873 // Test that the source line is correct when there is a line offset.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005874 v8::ScriptOrigin origin(v8_str(isolate, "test"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005875 v8::Integer::New(isolate, 7));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005876 v8::Script::Compile(context, v8_str(isolate, "CheckSourceLine(7)"), &origin)
5877 .ToLocalChecked()
5878 ->Run(context)
5879 .ToLocalChecked();
5880 v8::Script::Compile(context, v8_str(isolate,
5881 "function f() {\n"
5882 " CheckSourceLine(8)\n"
5883 " CheckSourceLine(9)\n"
5884 " CheckSourceLine(10)\n"
5885 "}; f()"),
5886 &origin)
5887 .ToLocalChecked()
5888 ->Run(context)
5889 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005890}
5891
5892
5893// Debugger message handler which counts the number of breaks.
5894static void SendContinueCommand();
5895static void MessageHandlerBreakPointHitCount(
5896 const v8::Debug::Message& message) {
5897 if (message.IsEvent() && message.GetEvent() == v8::Break) {
5898 // Count the number of breaks.
5899 break_point_hit_count++;
5900
5901 SendContinueCommand();
5902 }
5903}
5904
5905
5906// Test that clearing the debug event listener actually clears all break points
5907// and related information.
5908TEST(DebuggerUnload) {
5909 DebugLocalContext env;
5910
5911 // Check debugger is unloaded before it is used.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005912 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005913
5914 // Set a debug event listener.
5915 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005916 v8::Debug::SetDebugEventListener(env->GetIsolate(),
5917 DebugEventBreakPointHitCount);
5918 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00005919 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005920 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005921 // Create a couple of functions for the test.
5922 v8::Local<v8::Function> foo =
5923 CompileFunction(&env, "function foo(){x=1}", "foo");
5924 v8::Local<v8::Function> bar =
5925 CompileFunction(&env, "function bar(){y=2}", "bar");
5926
5927 // Set some break points.
5928 SetBreakPoint(foo, 0);
5929 SetBreakPoint(foo, 4);
5930 SetBreakPoint(bar, 0);
5931 SetBreakPoint(bar, 4);
5932
5933 // Make sure that the break points are there.
5934 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005935 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005936 CHECK_EQ(2, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005937 bar->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005938 CHECK_EQ(4, break_point_hit_count);
5939 }
5940
5941 // Remove the debug event listener without clearing breakpoints. Do this
5942 // outside a handle scope.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005943 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
5944 CheckDebuggerUnloaded(env->GetIsolate(), true);
Steve Blocka7e24c12009-10-30 11:49:00 +00005945
5946 // Now set a debug message handler.
5947 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005948 v8::Debug::SetMessageHandler(env->GetIsolate(),
5949 MessageHandlerBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00005950 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005951 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005952
5953 // Get the test functions again.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005954 v8::Local<v8::Function> foo(v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005955 env->Global()
5956 ->Get(context, v8_str(env->GetIsolate(), "foo"))
5957 .ToLocalChecked()));
Steve Blocka7e24c12009-10-30 11:49:00 +00005958
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005959 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005960 CHECK_EQ(0, break_point_hit_count);
5961
5962 // Set break points and run again.
5963 SetBreakPoint(foo, 0);
5964 SetBreakPoint(foo, 4);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005965 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005966 CHECK_EQ(2, break_point_hit_count);
5967 }
5968
5969 // Remove the debug message handler without clearing breakpoints. Do this
5970 // outside a handle scope.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005971 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
5972 CheckDebuggerUnloaded(env->GetIsolate(), true);
Steve Blocka7e24c12009-10-30 11:49:00 +00005973}
5974
5975
5976// Sends continue command to the debugger.
5977static void SendContinueCommand() {
5978 const int kBufferSize = 1000;
5979 uint16_t buffer[kBufferSize];
5980 const char* command_continue =
5981 "{\"seq\":0,"
5982 "\"type\":\"request\","
5983 "\"command\":\"continue\"}";
5984
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005985 v8::Debug::SendCommand(
5986 CcTest::isolate(), buffer, AsciiToUtf16(command_continue, buffer));
Steve Blocka7e24c12009-10-30 11:49:00 +00005987}
5988
5989
5990// Debugger message handler which counts the number of times it is called.
5991static int message_handler_hit_count = 0;
5992static void MessageHandlerHitCount(const v8::Debug::Message& message) {
5993 message_handler_hit_count++;
5994
Steve Block3ce2e202009-11-05 08:53:23 +00005995 static char print_buffer[1000];
5996 v8::String::Value json(message.GetJSON());
5997 Utf16ToAscii(*json, json.length(), print_buffer);
5998 if (IsExceptionEventMessage(print_buffer)) {
5999 // Send a continue command for exception events.
6000 SendContinueCommand();
6001 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006002}
6003
6004
6005// Test clearing the debug message handler.
6006TEST(DebuggerClearMessageHandler) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006007 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006008 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006009
6010 // Check debugger is unloaded before it is used.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006011 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006012
6013 // Set a debug message handler.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006014 v8::Debug::SetMessageHandler(env->GetIsolate(), MessageHandlerHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00006015
6016 // Run code to throw a unhandled exception. This should end up in the message
6017 // handler.
6018 CompileRun("throw 1");
6019
6020 // The message handler should be called.
6021 CHECK_GT(message_handler_hit_count, 0);
6022
6023 // Clear debug message handler.
6024 message_handler_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006025 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
Steve Blocka7e24c12009-10-30 11:49:00 +00006026
6027 // Run code to throw a unhandled exception. This should end up in the message
6028 // handler.
6029 CompileRun("throw 1");
6030
6031 // The message handler should not be called more.
6032 CHECK_EQ(0, message_handler_hit_count);
6033
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006034 CheckDebuggerUnloaded(env->GetIsolate(), true);
Steve Blocka7e24c12009-10-30 11:49:00 +00006035}
6036
6037
6038// Debugger message handler which clears the message handler while active.
6039static void MessageHandlerClearingMessageHandler(
6040 const v8::Debug::Message& message) {
6041 message_handler_hit_count++;
6042
6043 // Clear debug message handler.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006044 v8::Debug::SetMessageHandler(message.GetIsolate(), nullptr);
Steve Blocka7e24c12009-10-30 11:49:00 +00006045}
6046
6047
6048// Test clearing the debug message handler while processing a debug event.
6049TEST(DebuggerClearMessageHandlerWhileActive) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006050 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006051 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006052
6053 // Check debugger is unloaded before it is used.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006054 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006055
6056 // Set a debug message handler.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006057 v8::Debug::SetMessageHandler(env->GetIsolate(),
6058 MessageHandlerClearingMessageHandler);
Steve Blocka7e24c12009-10-30 11:49:00 +00006059
6060 // Run code to throw a unhandled exception. This should end up in the message
6061 // handler.
6062 CompileRun("throw 1");
6063
6064 // The message handler should be called.
6065 CHECK_EQ(1, message_handler_hit_count);
6066
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006067 CheckDebuggerUnloaded(env->GetIsolate(), true);
Steve Blocka7e24c12009-10-30 11:49:00 +00006068}
6069
6070
Steve Blocka7e24c12009-10-30 11:49:00 +00006071// Test for issue http://code.google.com/p/v8/issues/detail?id=289.
6072// Make sure that DebugGetLoadedScripts doesn't return scripts
6073// with disposed external source.
6074class EmptyExternalStringResource : public v8::String::ExternalStringResource {
6075 public:
6076 EmptyExternalStringResource() { empty_[0] = 0; }
6077 virtual ~EmptyExternalStringResource() {}
6078 virtual size_t length() const { return empty_.length(); }
6079 virtual const uint16_t* data() const { return empty_.start(); }
6080 private:
6081 ::v8::internal::EmbeddedVector<uint16_t, 1> empty_;
6082};
6083
Ben Murdoch61f157c2016-09-16 13:49:30 +01006084TEST(DebugScriptLineEndsAreAscending) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006085 DebugLocalContext env;
Ben Murdoch61f157c2016-09-16 13:49:30 +01006086 v8::Isolate* isolate = env->GetIsolate();
6087 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006088 env.ExposeDebug();
6089
Ben Murdoch61f157c2016-09-16 13:49:30 +01006090 // Compile a test script.
6091 v8::Local<v8::String> script = v8_str(isolate,
6092 "function f() {\n"
6093 " debugger;\n"
6094 "}\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00006095
Ben Murdoch61f157c2016-09-16 13:49:30 +01006096 v8::ScriptOrigin origin1 = v8::ScriptOrigin(v8_str(isolate, "name"));
6097 v8::Local<v8::Script> script1 =
6098 v8::Script::Compile(env.context(), script, &origin1).ToLocalChecked();
6099 USE(script1);
Steve Blocka7e24c12009-10-30 11:49:00 +00006100
Ben Murdoch61f157c2016-09-16 13:49:30 +01006101 Handle<v8::internal::FixedArray> instances;
6102 {
6103 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
6104 v8::internal::DebugScope debug_scope(debug);
6105 CHECK(!debug_scope.failed());
6106 instances = debug->GetLoadedScripts();
6107 }
6108
6109 CHECK_GT(instances->length(), 0);
6110 for (int i = 0; i < instances->length(); i++) {
6111 Handle<v8::internal::Script> script = Handle<v8::internal::Script>(
6112 v8::internal::Script::cast(instances->get(i)));
6113
6114 v8::internal::Script::InitLineEnds(script);
6115 v8::internal::FixedArray* ends =
6116 v8::internal::FixedArray::cast(script->line_ends());
6117 CHECK_GT(ends->length(), 0);
6118
6119 int prev_end = -1;
6120 for (int j = 0; j < ends->length(); j++) {
6121 const int curr_end = v8::internal::Smi::cast(ends->get(j))->value();
6122 CHECK_GT(curr_end, prev_end);
6123 prev_end = curr_end;
6124 }
6125 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006126}
6127
6128
6129// Test script break points set on lines.
6130TEST(ScriptNameAndData) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006131 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006132 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006133 env.ExposeDebug();
6134
6135 // Create functions for retrieving script name and data for the function on
6136 // the top frame when hitting a break point.
6137 frame_script_name = CompileFunction(&env,
6138 frame_script_name_source,
6139 "frame_script_name");
Steve Blocka7e24c12009-10-30 11:49:00 +00006140
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006141 v8::Debug::SetDebugEventListener(env->GetIsolate(),
6142 DebugEventBreakPointHitCount);
Steve Blocka7e24c12009-10-30 11:49:00 +00006143
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006144 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00006145 // Test function source.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006146 v8::Local<v8::String> script = v8_str(env->GetIsolate(),
6147 "function f() {\n"
6148 " debugger;\n"
6149 "}\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00006150
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006151 v8::ScriptOrigin origin1 =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006152 v8::ScriptOrigin(v8_str(env->GetIsolate(), "name"));
6153 v8::Local<v8::Script> script1 =
6154 v8::Script::Compile(context, script, &origin1).ToLocalChecked();
6155 script1->Run(context).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006156 v8::Local<v8::Function> f;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006157 f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006158 env->Global()
6159 ->Get(context, v8_str(env->GetIsolate(), "f"))
6160 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00006161
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006162 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006163 CHECK_EQ(1, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006164 CHECK_EQ(0, strcmp("name", last_script_name_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00006165
6166 // Compile the same script again without setting data. As the compilation
6167 // cache is disabled when debugging expect the data to be missing.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006168 v8::Script::Compile(context, script, &origin1)
6169 .ToLocalChecked()
6170 ->Run(context)
6171 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006172 f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006173 env->Global()
6174 ->Get(context, v8_str(env->GetIsolate(), "f"))
6175 .ToLocalChecked());
6176 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006177 CHECK_EQ(2, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006178 CHECK_EQ(0, strcmp("name", last_script_name_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00006179
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006180 v8::Local<v8::String> data_obj_source =
6181 v8_str(env->GetIsolate(),
6182 "({ a: 'abc',\n"
6183 " b: 123,\n"
6184 " toString: function() { return this.a + ' ' + this.b; }\n"
6185 "})\n");
6186 v8::Script::Compile(context, data_obj_source)
6187 .ToLocalChecked()
6188 ->Run(context)
6189 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006190 v8::ScriptOrigin origin2 =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006191 v8::ScriptOrigin(v8_str(env->GetIsolate(), "new name"));
6192 v8::Local<v8::Script> script2 =
6193 v8::Script::Compile(context, script, &origin2).ToLocalChecked();
6194 script2->Run(context).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006195 f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006196 env->Global()
6197 ->Get(context, v8_str(env->GetIsolate(), "f"))
6198 .ToLocalChecked());
6199 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006200 CHECK_EQ(3, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006201 CHECK_EQ(0, strcmp("new name", last_script_name_hit));
Andrei Popescu402d9372010-02-26 13:31:12 +00006202
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006203 v8::Local<v8::Script> script3 =
6204 v8::Script::Compile(context, script, &origin2).ToLocalChecked();
6205 script3->Run(context).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006206 f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006207 env->Global()
6208 ->Get(context, v8_str(env->GetIsolate(), "f"))
6209 .ToLocalChecked());
6210 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Andrei Popescu402d9372010-02-26 13:31:12 +00006211 CHECK_EQ(4, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00006212}
6213
6214
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006215static v8::Local<v8::Context> expected_context;
6216static v8::Local<v8::Value> expected_context_data;
Steve Blocka7e24c12009-10-30 11:49:00 +00006217
6218
6219// Check that the expected context is the one generating the debug event.
6220static void ContextCheckMessageHandler(const v8::Debug::Message& message) {
6221 CHECK(message.GetEventContext() == expected_context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006222 CHECK(message.GetEventContext()->GetEmbedderData(0)->StrictEquals(
Steve Blocka7e24c12009-10-30 11:49:00 +00006223 expected_context_data));
6224 message_handler_hit_count++;
6225
Steve Block3ce2e202009-11-05 08:53:23 +00006226 static char print_buffer[1000];
6227 v8::String::Value json(message.GetJSON());
6228 Utf16ToAscii(*json, json.length(), print_buffer);
6229
Steve Blocka7e24c12009-10-30 11:49:00 +00006230 // Send a continue command for break events.
Steve Block3ce2e202009-11-05 08:53:23 +00006231 if (IsBreakEventMessage(print_buffer)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006232 SendContinueCommand();
6233 }
6234}
6235
6236
6237// Test which creates two contexts and sets different embedder data on each.
6238// Checks that this data is set correctly and that when the debug message
6239// handler is called the expected context is the one active.
6240TEST(ContextData) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006241 v8::Isolate* isolate = CcTest::isolate();
6242 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006243
6244 // Create two contexts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006245 v8::Local<v8::Context> context_1;
6246 v8::Local<v8::Context> context_2;
6247 v8::Local<v8::ObjectTemplate> global_template =
6248 v8::Local<v8::ObjectTemplate>();
6249 v8::Local<v8::Value> global_object = v8::Local<v8::Value>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006250 context_1 = v8::Context::New(isolate, NULL, global_template, global_object);
6251 context_2 = v8::Context::New(isolate, NULL, global_template, global_object);
6252
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006253 v8::Debug::SetMessageHandler(isolate, ContextCheckMessageHandler);
Steve Blocka7e24c12009-10-30 11:49:00 +00006254
6255 // Default data value is undefined.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006256 CHECK(context_1->GetEmbedderData(0)->IsUndefined());
6257 CHECK(context_2->GetEmbedderData(0)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00006258
6259 // Set and check different data values.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006260 v8::Local<v8::String> data_1 = v8_str(isolate, "1");
6261 v8::Local<v8::String> data_2 = v8_str(isolate, "2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006262 context_1->SetEmbedderData(0, data_1);
6263 context_2->SetEmbedderData(0, data_2);
6264 CHECK(context_1->GetEmbedderData(0)->StrictEquals(data_1));
6265 CHECK(context_2->GetEmbedderData(0)->StrictEquals(data_2));
Steve Blocka7e24c12009-10-30 11:49:00 +00006266
6267 // Simple test function which causes a break.
6268 const char* source = "function f() { debugger; }";
6269
6270 // Enter and run function in the first context.
6271 {
6272 v8::Context::Scope context_scope(context_1);
6273 expected_context = context_1;
6274 expected_context_data = data_1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006275 v8::Local<v8::Function> f = CompileFunction(isolate, source, "f");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006276 f->Call(context_1, context_1->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006277 }
6278
6279
6280 // Enter and run function in the second context.
6281 {
6282 v8::Context::Scope context_scope(context_2);
6283 expected_context = context_2;
6284 expected_context_data = data_2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006285 v8::Local<v8::Function> f = CompileFunction(isolate, source, "f");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006286 f->Call(context_2, context_2->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006287 }
6288
6289 // Two times compile event and two times break event.
6290 CHECK_GT(message_handler_hit_count, 4);
6291
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006292 v8::Debug::SetMessageHandler(isolate, nullptr);
6293 CheckDebuggerUnloaded(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006294}
6295
6296
6297// Debug message handler which issues a debug break when it hits a break event.
6298static int message_handler_break_hit_count = 0;
6299static void DebugBreakMessageHandler(const v8::Debug::Message& message) {
6300 // Schedule a debug break for break events.
6301 if (message.IsEvent() && message.GetEvent() == v8::Break) {
6302 message_handler_break_hit_count++;
6303 if (message_handler_break_hit_count == 1) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006304 v8::Debug::DebugBreak(message.GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006305 }
6306 }
6307
6308 // Issue a continue command if this event will not cause the VM to start
6309 // running.
6310 if (!message.WillStartRunning()) {
6311 SendContinueCommand();
6312 }
6313}
6314
6315
6316// Test that a debug break can be scheduled while in a message handler.
6317TEST(DebugBreakInMessageHandler) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006318 i::FLAG_turbo_inlining = false; // Make sure g is not inlined into f.
Steve Blocka7e24c12009-10-30 11:49:00 +00006319 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006320 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006321
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006322 v8::Debug::SetMessageHandler(env->GetIsolate(), DebugBreakMessageHandler);
Steve Blocka7e24c12009-10-30 11:49:00 +00006323
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006324 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00006325 // Test functions.
6326 const char* script = "function f() { debugger; g(); } function g() { }";
6327 CompileRun(script);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006328 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006329 env->Global()
6330 ->Get(context, v8_str(env->GetIsolate(), "f"))
6331 .ToLocalChecked());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006332 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006333 env->Global()
6334 ->Get(context, v8_str(env->GetIsolate(), "g"))
6335 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +00006336
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006337 // Call f then g. The debugger statement in f will cause a break which will
Steve Blocka7e24c12009-10-30 11:49:00 +00006338 // cause another break.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006339 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006340 CHECK_EQ(2, message_handler_break_hit_count);
6341 // Calling g will not cause any additional breaks.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006342 g->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006343 CHECK_EQ(2, message_handler_break_hit_count);
6344}
6345
6346
Steve Block6ded16b2010-05-10 14:33:55 +01006347#ifndef V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +00006348// Debug event handler which gets the function on the top frame and schedules a
6349// break a number of times.
6350static void DebugEventDebugBreak(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006351 const v8::Debug::EventDetails& event_details) {
6352 v8::DebugEvent event = event_details.GetEvent();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006353 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
6354 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
Steve Blocka7e24c12009-10-30 11:49:00 +00006355 if (event == v8::Break) {
6356 break_point_hit_count++;
6357
6358 // Get the name of the top frame function.
6359 if (!frame_function_name.IsEmpty()) {
6360 // Get the name of the function.
Ben Murdochb0fe1622011-05-05 13:52:32 +01006361 const int argc = 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006362 v8::Local<v8::Value> argv[argc] = {
6363 exec_state, v8::Integer::New(CcTest::isolate(), 0)};
6364 v8::Local<v8::Value> result =
6365 frame_function_name->Call(context, exec_state, argc, argv)
6366 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006367 if (result->IsUndefined()) {
6368 last_function_hit[0] = '\0';
6369 } else {
6370 CHECK(result->IsString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006371 v8::Local<v8::String> function_name(
6372 result->ToString(context).ToLocalChecked());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006373 function_name->WriteUtf8(last_function_hit);
Steve Blocka7e24c12009-10-30 11:49:00 +00006374 }
6375 }
6376
6377 // Keep forcing breaks.
6378 if (break_point_hit_count < 20) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006379 v8::Debug::DebugBreak(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006380 }
6381 }
6382}
6383
6384
6385TEST(RegExpDebugBreak) {
6386 // This test only applies to native regexps.
Steve Blocka7e24c12009-10-30 11:49:00 +00006387 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006388 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006389 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00006390 // Create a function for checking the function when hitting a break point.
6391 frame_function_name = CompileFunction(&env,
6392 frame_function_name_source,
6393 "frame_function_name");
6394
6395 // Test RegExp which matches white spaces and comments at the begining of a
6396 // source line.
6397 const char* script =
6398 "var sourceLineBeginningSkip = /^(?:[ \\v\\h]*(?:\\/\\*.*?\\*\\/)*)*/;\n"
6399 "function f(s) { return s.match(sourceLineBeginningSkip)[0].length; }";
6400
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006401 v8::Local<v8::Function> f = CompileFunction(env->GetIsolate(), script, "f");
Steve Blocka7e24c12009-10-30 11:49:00 +00006402 const int argc = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006403 v8::Local<v8::Value> argv[argc] = {
6404 v8_str(env->GetIsolate(), " /* xxx */ a=0;")};
6405 v8::Local<v8::Value> result =
6406 f->Call(context, env->Global(), argc, argv).ToLocalChecked();
6407 CHECK_EQ(12, result->Int32Value(context).FromJust());
Steve Blocka7e24c12009-10-30 11:49:00 +00006408
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006409 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventDebugBreak);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006410 v8::Debug::DebugBreak(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006411 result = f->Call(context, env->Global(), argc, argv).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006412
6413 // Check that there was only one break event. Matching RegExp should not
6414 // cause Break events.
6415 CHECK_EQ(1, break_point_hit_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006416 CHECK_EQ(0, strcmp("f", last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00006417}
Steve Block6ded16b2010-05-10 14:33:55 +01006418#endif // V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +00006419
6420
6421// Common part of EvalContextData and NestedBreakEventContextData tests.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006422static void ExecuteScriptForContextCheck(
6423 v8::Debug::MessageHandler message_handler) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006424 // Create a context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006425 v8::Local<v8::Context> context_1;
6426 v8::Local<v8::ObjectTemplate> global_template =
6427 v8::Local<v8::ObjectTemplate>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006428 context_1 =
6429 v8::Context::New(CcTest::isolate(), NULL, global_template);
6430
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006431 v8::Debug::SetMessageHandler(CcTest::isolate(), message_handler);
Steve Blocka7e24c12009-10-30 11:49:00 +00006432
6433 // Default data value is undefined.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006434 CHECK(context_1->GetEmbedderData(0)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00006435
6436 // Set and check a data value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006437 v8::Local<v8::String> data_1 = v8_str(CcTest::isolate(), "1");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006438 context_1->SetEmbedderData(0, data_1);
6439 CHECK(context_1->GetEmbedderData(0)->StrictEquals(data_1));
Steve Blocka7e24c12009-10-30 11:49:00 +00006440
6441 // Simple test function with eval that causes a break.
6442 const char* source = "function f() { eval('debugger;'); }";
6443
6444 // Enter and run function in the context.
6445 {
6446 v8::Context::Scope context_scope(context_1);
6447 expected_context = context_1;
6448 expected_context_data = data_1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006449 v8::Local<v8::Function> f = CompileFunction(CcTest::isolate(), source, "f");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006450 f->Call(context_1, context_1->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006451 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006452
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006453 v8::Debug::SetMessageHandler(CcTest::isolate(), nullptr);
Steve Blocka7e24c12009-10-30 11:49:00 +00006454}
6455
6456
6457// Test which creates a context and sets embedder data on it. Checks that this
6458// data is set correctly and that when the debug message handler is called for
6459// break event in an eval statement the expected context is the one returned by
6460// Message.GetEventContext.
6461TEST(EvalContextData) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006462 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006463
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006464 ExecuteScriptForContextCheck(ContextCheckMessageHandler);
Steve Blocka7e24c12009-10-30 11:49:00 +00006465
6466 // One time compile event and one time break event.
6467 CHECK_GT(message_handler_hit_count, 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006468 CheckDebuggerUnloaded(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006469}
6470
6471
6472static bool sent_eval = false;
6473static int break_count = 0;
6474static int continue_command_send_count = 0;
6475// Check that the expected context is the one generating the debug event
6476// including the case of nested break event.
6477static void DebugEvalContextCheckMessageHandler(
6478 const v8::Debug::Message& message) {
6479 CHECK(message.GetEventContext() == expected_context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006480 CHECK(message.GetEventContext()->GetEmbedderData(0)->StrictEquals(
Steve Blocka7e24c12009-10-30 11:49:00 +00006481 expected_context_data));
6482 message_handler_hit_count++;
6483
Steve Block3ce2e202009-11-05 08:53:23 +00006484 static char print_buffer[1000];
6485 v8::String::Value json(message.GetJSON());
6486 Utf16ToAscii(*json, json.length(), print_buffer);
6487
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006488 v8::Isolate* isolate = message.GetIsolate();
Steve Block3ce2e202009-11-05 08:53:23 +00006489 if (IsBreakEventMessage(print_buffer)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006490 break_count++;
6491 if (!sent_eval) {
6492 sent_eval = true;
6493
6494 const int kBufferSize = 1000;
6495 uint16_t buffer[kBufferSize];
6496 const char* eval_command =
Ben Murdoch257744e2011-11-30 15:57:28 +00006497 "{\"seq\":0,"
6498 "\"type\":\"request\","
6499 "\"command\":\"evaluate\","
6500 "\"arguments\":{\"expression\":\"debugger;\","
6501 "\"global\":true,\"disable_break\":false}}";
Steve Blocka7e24c12009-10-30 11:49:00 +00006502
6503 // Send evaluate command.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006504 v8::Debug::SendCommand(
6505 isolate, buffer, AsciiToUtf16(eval_command, buffer));
Steve Blocka7e24c12009-10-30 11:49:00 +00006506 return;
6507 } else {
6508 // It's a break event caused by the evaluation request above.
6509 SendContinueCommand();
6510 continue_command_send_count++;
6511 }
Steve Block3ce2e202009-11-05 08:53:23 +00006512 } else if (IsEvaluateResponseMessage(print_buffer) &&
6513 continue_command_send_count < 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006514 // Response to the evaluation request. We're still on the breakpoint so
6515 // send continue.
6516 SendContinueCommand();
6517 continue_command_send_count++;
6518 }
6519}
6520
6521
6522// Tests that context returned for break event is correct when the event occurs
6523// in 'evaluate' debugger request.
6524TEST(NestedBreakEventContextData) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006525 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006526 break_count = 0;
6527 message_handler_hit_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00006528
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006529 ExecuteScriptForContextCheck(DebugEvalContextCheckMessageHandler);
Steve Blocka7e24c12009-10-30 11:49:00 +00006530
6531 // One time compile event and two times break event.
6532 CHECK_GT(message_handler_hit_count, 3);
6533
6534 // One break from the source and another from the evaluate request.
6535 CHECK_EQ(break_count, 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006536 CheckDebuggerUnloaded(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006537}
6538
6539
Steve Blocka7e24c12009-10-30 11:49:00 +00006540// Debug event listener which counts the after compile events.
6541int after_compile_message_count = 0;
6542static void AfterCompileMessageHandler(const v8::Debug::Message& message) {
6543 // Count the number of scripts collected.
6544 if (message.IsEvent()) {
6545 if (message.GetEvent() == v8::AfterCompile) {
6546 after_compile_message_count++;
6547 } else if (message.GetEvent() == v8::Break) {
6548 SendContinueCommand();
6549 }
6550 }
6551}
6552
6553
6554// Tests that after compile event is sent as many times as there are scripts
6555// compiled.
6556TEST(AfterCompileMessageWhenMessageHandlerIsReset) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006557 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006558 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006559 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00006560 after_compile_message_count = 0;
6561 const char* script = "var a=1";
6562
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006563 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler);
6564 v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
6565 .ToLocalChecked()
6566 ->Run(context)
6567 .ToLocalChecked();
6568 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
Steve Blocka7e24c12009-10-30 11:49:00 +00006569
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006570 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006571 v8::Debug::DebugBreak(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006572 v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
6573 .ToLocalChecked()
6574 ->Run(context)
6575 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006576
6577 // Setting listener to NULL should cause debugger unload.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006578 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
6579 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006580
6581 // Compilation cache should be disabled when debugger is active.
6582 CHECK_EQ(2, after_compile_message_count);
6583}
6584
6585
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006586// Syntax error event handler which counts a number of events.
6587int compile_error_event_count = 0;
6588
6589static void CompileErrorEventCounterClear() {
6590 compile_error_event_count = 0;
6591}
6592
6593static void CompileErrorEventCounter(
6594 const v8::Debug::EventDetails& event_details) {
6595 v8::DebugEvent event = event_details.GetEvent();
6596
6597 if (event == v8::CompileError) {
6598 compile_error_event_count++;
6599 }
6600}
6601
6602
6603// Tests that syntax error event is sent as many times as there are scripts
6604// with syntax error compiled.
6605TEST(SyntaxErrorMessageOnSyntaxException) {
6606 DebugLocalContext env;
6607 v8::HandleScope scope(env->GetIsolate());
6608
6609 // For this test, we want to break on uncaught exceptions:
6610 ChangeBreakOnException(false, true);
6611
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006612 v8::Debug::SetDebugEventListener(env->GetIsolate(), CompileErrorEventCounter);
6613 v8::Local<v8::Context> context = env.context();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006614
6615 CompileErrorEventCounterClear();
6616
6617 // Check initial state.
6618 CHECK_EQ(0, compile_error_event_count);
6619
6620 // Throws SyntaxError: Unexpected end of input
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006621 CHECK(
6622 v8::Script::Compile(context, v8_str(env->GetIsolate(), "+++")).IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006623 CHECK_EQ(1, compile_error_event_count);
6624
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006625 CHECK(v8::Script::Compile(context, v8_str(env->GetIsolate(), "/sel\\/: \\"))
6626 .IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006627 CHECK_EQ(2, compile_error_event_count);
6628
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006629 v8::Local<v8::Script> script =
6630 v8::Script::Compile(context,
6631 v8_str(env->GetIsolate(), "JSON.parse('1234:')"))
6632 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006633 CHECK_EQ(2, compile_error_event_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006634 CHECK(script->Run(context).IsEmpty());
6635 CHECK_EQ(3, compile_error_event_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006636
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006637 v8::Script::Compile(context,
6638 v8_str(env->GetIsolate(), "new RegExp('/\\/\\\\');"))
6639 .ToLocalChecked();
6640 CHECK_EQ(3, compile_error_event_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006641
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006642 v8::Script::Compile(context, v8_str(env->GetIsolate(), "throw 1;"))
6643 .ToLocalChecked();
6644 CHECK_EQ(3, compile_error_event_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006645}
6646
6647
Steve Blocka7e24c12009-10-30 11:49:00 +00006648// Tests that break event is sent when message handler is reset.
6649TEST(BreakMessageWhenMessageHandlerIsReset) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006650 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006651 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006652 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00006653 after_compile_message_count = 0;
6654 const char* script = "function f() {};";
6655
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006656 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler);
6657 v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
6658 .ToLocalChecked()
6659 ->Run(context)
6660 .ToLocalChecked();
6661 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
Steve Blocka7e24c12009-10-30 11:49:00 +00006662
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006663 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006664 v8::Debug::DebugBreak(env->GetIsolate());
6665 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006666 env->Global()
6667 ->Get(context, v8_str(env->GetIsolate(), "f"))
6668 .ToLocalChecked());
6669 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006670
6671 // Setting message handler to NULL should cause debugger unload.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006672 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
6673 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006674
6675 // Compilation cache should be disabled when debugger is active.
6676 CHECK_EQ(1, after_compile_message_count);
6677}
6678
6679
6680static int exception_event_count = 0;
6681static void ExceptionMessageHandler(const v8::Debug::Message& message) {
6682 if (message.IsEvent() && message.GetEvent() == v8::Exception) {
6683 exception_event_count++;
6684 SendContinueCommand();
6685 }
6686}
6687
6688
6689// Tests that exception event is sent when message handler is reset.
6690TEST(ExceptionMessageWhenMessageHandlerIsReset) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006691 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006692 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch086aeea2011-05-13 15:57:08 +01006693
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006694 v8::Local<v8::Context> context = env.context();
Ben Murdoch086aeea2011-05-13 15:57:08 +01006695 // For this test, we want to break on uncaught exceptions:
6696 ChangeBreakOnException(false, true);
6697
Steve Blocka7e24c12009-10-30 11:49:00 +00006698 exception_event_count = 0;
6699 const char* script = "function f() {throw new Error()};";
6700
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006701 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler);
6702 v8::Script::Compile(context, v8_str(env->GetIsolate(), script))
6703 .ToLocalChecked()
6704 ->Run(context)
6705 .ToLocalChecked();
6706 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
Steve Blocka7e24c12009-10-30 11:49:00 +00006707
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006708 v8::Debug::SetMessageHandler(env->GetIsolate(), ExceptionMessageHandler);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006709 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006710 env->Global()
6711 ->Get(context, v8_str(env->GetIsolate(), "f"))
6712 .ToLocalChecked());
6713 CHECK(f->Call(context, env->Global(), 0, NULL).IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00006714
6715 // Setting message handler to NULL should cause debugger unload.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006716 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
6717 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006718
6719 CHECK_EQ(1, exception_event_count);
6720}
6721
6722
6723// Tests after compile event is sent when there are some provisional
6724// breakpoints out of the scripts lines range.
6725TEST(ProvisionalBreakpointOnLineOutOfRange) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006726 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006727 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006728 env.ExposeDebug();
6729 const char* script = "function f() {};";
6730 const char* resource_name = "test_resource";
6731
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006732 v8::Debug::SetMessageHandler(env->GetIsolate(), AfterCompileMessageHandler);
6733 v8::Local<v8::Context> context = env.context();
6734
Steve Blocka7e24c12009-10-30 11:49:00 +00006735 // Set a couple of provisional breakpoint on lines out of the script lines
6736 // range.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006737 int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name,
6738 3, -1 /* no column */);
6739 int sbp2 =
6740 SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name, 5, 5);
Steve Blocka7e24c12009-10-30 11:49:00 +00006741
6742 after_compile_message_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00006743
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006744 v8::ScriptOrigin origin(v8_str(env->GetIsolate(), resource_name),
6745 v8::Integer::New(env->GetIsolate(), 10),
6746 v8::Integer::New(env->GetIsolate(), 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00006747 // Compile a script whose first line number is greater than the breakpoints'
6748 // lines.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006749 v8::Script::Compile(context, v8_str(env->GetIsolate(), script), &origin)
6750 .ToLocalChecked()
6751 ->Run(context)
6752 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006753
6754 // If the script is compiled successfully there is exactly one after compile
6755 // event. In case of an exception in debugger code after compile event is not
6756 // sent.
6757 CHECK_EQ(1, after_compile_message_count);
6758
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006759 ClearBreakPointFromJS(env->GetIsolate(), sbp1);
6760 ClearBreakPointFromJS(env->GetIsolate(), sbp2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006761 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
Steve Blocka7e24c12009-10-30 11:49:00 +00006762}
6763
6764
6765static void BreakMessageHandler(const v8::Debug::Message& message) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006766 i::Isolate* isolate = CcTest::i_isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00006767 if (message.IsEvent() && message.GetEvent() == v8::Break) {
6768 // Count the number of breaks.
6769 break_point_hit_count++;
6770
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006771 i::HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006772 message.GetJSON();
Steve Blocka7e24c12009-10-30 11:49:00 +00006773
6774 SendContinueCommand();
6775 } else if (message.IsEvent() && message.GetEvent() == v8::AfterCompile) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006776 i::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006777
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006778 int current_count = break_point_hit_count;
Steve Blocka7e24c12009-10-30 11:49:00 +00006779
6780 // Force serialization to trigger some internal JS execution.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006781 message.GetJSON();
Steve Blocka7e24c12009-10-30 11:49:00 +00006782
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006783 CHECK_EQ(current_count, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00006784 }
6785}
6786
6787
6788// Test that if DebugBreak is forced it is ignored when code from
6789// debug-delay.js is executed.
6790TEST(NoDebugBreakInAfterCompileMessageHandler) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006791 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006792 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006793 v8::Local<v8::Context> context = env.context();
Steve Blocka7e24c12009-10-30 11:49:00 +00006794
6795 // Register a debug event listener which sets the break flag and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006796 v8::Debug::SetMessageHandler(env->GetIsolate(), BreakMessageHandler);
Steve Blocka7e24c12009-10-30 11:49:00 +00006797
6798 // Set the debug break flag.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006799 v8::Debug::DebugBreak(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006800
6801 // Create a function for testing stepping.
6802 const char* src = "function f() { eval('var x = 10;'); } ";
6803 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
6804
6805 // There should be only one break event.
6806 CHECK_EQ(1, break_point_hit_count);
6807
6808 // Set the debug break flag again.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006809 v8::Debug::DebugBreak(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006810 f->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00006811 // There should be one more break event when the script is evaluated in 'f'.
6812 CHECK_EQ(2, break_point_hit_count);
6813
6814 // Get rid of the debug message handler.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006815 v8::Debug::SetMessageHandler(env->GetIsolate(), nullptr);
6816 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006817}
6818
6819
Leon Clarkee46be812010-01-19 14:06:41 +00006820static int counting_message_handler_counter;
6821
6822static void CountingMessageHandler(const v8::Debug::Message& message) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006823 if (message.IsResponse()) counting_message_handler_counter++;
Leon Clarkee46be812010-01-19 14:06:41 +00006824}
6825
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006826
Leon Clarkee46be812010-01-19 14:06:41 +00006827// Test that debug messages get processed when ProcessDebugMessages is called.
6828TEST(ProcessDebugMessages) {
Leon Clarkee46be812010-01-19 14:06:41 +00006829 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006830 v8::Isolate* isolate = env->GetIsolate();
6831 v8::HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00006832
6833 counting_message_handler_counter = 0;
6834
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006835 v8::Debug::SetMessageHandler(isolate, CountingMessageHandler);
Leon Clarkee46be812010-01-19 14:06:41 +00006836
6837 const int kBufferSize = 1000;
6838 uint16_t buffer[kBufferSize];
6839 const char* scripts_command =
6840 "{\"seq\":0,"
6841 "\"type\":\"request\","
6842 "\"command\":\"scripts\"}";
6843
6844 // Send scripts command.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006845 v8::Debug::SendCommand(
6846 isolate, buffer, AsciiToUtf16(scripts_command, buffer));
Leon Clarkee46be812010-01-19 14:06:41 +00006847
6848 CHECK_EQ(0, counting_message_handler_counter);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006849 v8::Debug::ProcessDebugMessages(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00006850 // At least one message should come
6851 CHECK_GE(counting_message_handler_counter, 1);
6852
6853 counting_message_handler_counter = 0;
6854
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006855 v8::Debug::SendCommand(
6856 isolate, buffer, AsciiToUtf16(scripts_command, buffer));
6857 v8::Debug::SendCommand(
6858 isolate, buffer, AsciiToUtf16(scripts_command, buffer));
Leon Clarkee46be812010-01-19 14:06:41 +00006859 CHECK_EQ(0, counting_message_handler_counter);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006860 v8::Debug::ProcessDebugMessages(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00006861 // At least two messages should come
6862 CHECK_GE(counting_message_handler_counter, 2);
6863
6864 // Get rid of the debug message handler.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006865 v8::Debug::SetMessageHandler(isolate, nullptr);
6866 CheckDebuggerUnloaded(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006867}
6868
6869
6870class SendCommandThread;
6871static SendCommandThread* send_command_thread_ = NULL;
6872
6873
6874class SendCommandThread : public v8::base::Thread {
6875 public:
6876 explicit SendCommandThread(v8::Isolate* isolate)
6877 : Thread(Options("SendCommandThread")),
6878 semaphore_(0),
6879 isolate_(isolate) {}
6880
6881 static void CountingAndSignallingMessageHandler(
6882 const v8::Debug::Message& message) {
6883 if (message.IsResponse()) {
6884 counting_message_handler_counter++;
6885 send_command_thread_->semaphore_.Signal();
6886 }
6887 }
6888
6889 virtual void Run() {
6890 semaphore_.Wait();
6891 const int kBufferSize = 1000;
6892 uint16_t buffer[kBufferSize];
6893 const char* scripts_command =
6894 "{\"seq\":0,"
6895 "\"type\":\"request\","
6896 "\"command\":\"scripts\"}";
6897 int length = AsciiToUtf16(scripts_command, buffer);
6898 // Send scripts command.
6899
6900 for (int i = 0; i < 20; i++) {
6901 v8::base::ElapsedTimer timer;
6902 timer.Start();
6903 CHECK_EQ(i, counting_message_handler_counter);
6904 // Queue debug message.
6905 v8::Debug::SendCommand(isolate_, buffer, length);
6906 // Wait for the message handler to pick up the response.
6907 semaphore_.Wait();
6908 i::PrintF("iteration %d took %f ms\n", i,
6909 timer.Elapsed().InMillisecondsF());
6910 }
6911
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006912 isolate_->TerminateExecution();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006913 }
6914
6915 void StartSending() { semaphore_.Signal(); }
6916
6917 private:
6918 v8::base::Semaphore semaphore_;
6919 v8::Isolate* isolate_;
6920};
6921
6922
6923static void StartSendingCommands(
6924 const v8::FunctionCallbackInfo<v8::Value>& info) {
6925 send_command_thread_->StartSending();
6926}
6927
6928
6929TEST(ProcessDebugMessagesThreaded) {
6930 DebugLocalContext env;
6931 v8::Isolate* isolate = env->GetIsolate();
6932 v8::HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006933 v8::Local<v8::Context> context = env.context();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006934
6935 counting_message_handler_counter = 0;
6936
6937 v8::Debug::SetMessageHandler(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006938 isolate, SendCommandThread::CountingAndSignallingMessageHandler);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006939 send_command_thread_ = new SendCommandThread(isolate);
6940 send_command_thread_->Start();
6941
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006942 v8::Local<v8::FunctionTemplate> start =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006943 v8::FunctionTemplate::New(isolate, StartSendingCommands);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006944 CHECK(env->Global()
6945 ->Set(context, v8_str("start"),
6946 start->GetFunction(context).ToLocalChecked())
6947 .FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006948
6949 CompileRun("start(); while (true) { }");
6950
6951 CHECK_EQ(20, counting_message_handler_counter);
6952
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006953 v8::Debug::SetMessageHandler(isolate, nullptr);
6954 CheckDebuggerUnloaded(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00006955}
6956
6957
Steve Block6ded16b2010-05-10 14:33:55 +01006958struct BacktraceData {
Leon Clarked91b9f72010-01-27 17:25:45 +00006959 static int frame_counter;
6960 static void MessageHandler(const v8::Debug::Message& message) {
6961 char print_buffer[1000];
6962 v8::String::Value json(message.GetJSON());
6963 Utf16ToAscii(*json, json.length(), print_buffer, 1000);
6964
6965 if (strstr(print_buffer, "backtrace") == NULL) {
6966 return;
6967 }
6968 frame_counter = GetTotalFramesInt(print_buffer);
6969 }
6970};
6971
Steve Block6ded16b2010-05-10 14:33:55 +01006972int BacktraceData::frame_counter;
Leon Clarked91b9f72010-01-27 17:25:45 +00006973
6974
6975// Test that debug messages get processed when ProcessDebugMessages is called.
6976TEST(Backtrace) {
Leon Clarked91b9f72010-01-27 17:25:45 +00006977 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006978 v8::Isolate* isolate = env->GetIsolate();
6979 v8::HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006980 v8::Local<v8::Context> context = env.context();
Leon Clarked91b9f72010-01-27 17:25:45 +00006981
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006982 v8::Debug::SetMessageHandler(isolate, BacktraceData::MessageHandler);
Leon Clarked91b9f72010-01-27 17:25:45 +00006983
6984 const int kBufferSize = 1000;
6985 uint16_t buffer[kBufferSize];
6986 const char* scripts_command =
6987 "{\"seq\":0,"
6988 "\"type\":\"request\","
6989 "\"command\":\"backtrace\"}";
6990
6991 // Check backtrace from ProcessDebugMessages.
Steve Block6ded16b2010-05-10 14:33:55 +01006992 BacktraceData::frame_counter = -10;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006993 v8::Debug::SendCommand(
6994 isolate,
6995 buffer,
6996 AsciiToUtf16(scripts_command, buffer),
6997 NULL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006998 v8::Debug::ProcessDebugMessages(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01006999 CHECK_EQ(BacktraceData::frame_counter, 0);
Leon Clarked91b9f72010-01-27 17:25:45 +00007000
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007001 v8::Local<v8::String> void0 = v8_str(env->GetIsolate(), "void(0)");
7002 v8::Local<v8::Script> script = CompileWithOrigin(void0, void0);
Leon Clarked91b9f72010-01-27 17:25:45 +00007003
7004 // Check backtrace from "void(0)" script.
Steve Block6ded16b2010-05-10 14:33:55 +01007005 BacktraceData::frame_counter = -10;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007006 v8::Debug::SendCommand(
7007 isolate,
7008 buffer,
7009 AsciiToUtf16(scripts_command, buffer),
7010 NULL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007011 script->Run(context).ToLocalChecked();
Steve Block6ded16b2010-05-10 14:33:55 +01007012 CHECK_EQ(BacktraceData::frame_counter, 1);
Leon Clarked91b9f72010-01-27 17:25:45 +00007013
7014 // Get rid of the debug message handler.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007015 v8::Debug::SetMessageHandler(isolate, nullptr);
7016 CheckDebuggerUnloaded(isolate);
Leon Clarked91b9f72010-01-27 17:25:45 +00007017}
7018
7019
Steve Blocka7e24c12009-10-30 11:49:00 +00007020TEST(GetMirror) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007021 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007022 v8::Isolate* isolate = env->GetIsolate();
7023 v8::HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007024 v8::Local<v8::Context> context = env.context();
7025 v8::Local<v8::Value> obj =
7026 v8::Debug::GetMirror(context, v8_str(isolate, "hodja")).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007027 v8::ScriptCompiler::Source source(v8_str(
7028 "function runTest(mirror) {"
7029 " return mirror.isString() && (mirror.length() == 5);"
7030 "}"
7031 ""
7032 "runTest;"));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007033 v8::Local<v8::Function> run_test = v8::Local<v8::Function>::Cast(
7034 v8::ScriptCompiler::CompileUnboundScript(isolate, &source)
7035 .ToLocalChecked()
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007036 ->BindToCurrentContext()
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007037 ->Run(context)
7038 .ToLocalChecked());
7039 v8::Local<v8::Value> result =
7040 run_test->Call(context, env->Global(), 1, &obj).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00007041 CHECK(result->IsTrue());
7042}
Steve Blockd0582a62009-12-15 09:54:21 +00007043
7044
7045// Test that the debug break flag works with function.apply.
7046TEST(DebugBreakFunctionApply) {
Steve Blockd0582a62009-12-15 09:54:21 +00007047 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007048 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007049 v8::Local<v8::Context> context = env.context();
Steve Blockd0582a62009-12-15 09:54:21 +00007050
7051 // Create a function for testing breaking in apply.
7052 v8::Local<v8::Function> foo = CompileFunction(
7053 &env,
7054 "function baz(x) { }"
7055 "function bar(x) { baz(); }"
7056 "function foo(){ bar.apply(this, [1]); }",
7057 "foo");
7058
7059 // Register a debug event listener which steps and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007060 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventBreakMax);
Steve Blockd0582a62009-12-15 09:54:21 +00007061
7062 // Set the debug break flag before calling the code using function.apply.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007063 v8::Debug::DebugBreak(env->GetIsolate());
Steve Blockd0582a62009-12-15 09:54:21 +00007064
7065 // Limit the number of debug breaks. This is a regression test for issue 493
7066 // where this test would enter an infinite loop.
7067 break_point_hit_count = 0;
7068 max_break_point_hit_count = 10000; // 10000 => infinite loop.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007069 foo->Call(context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00007070
7071 // When keeping the debug break several break will happen.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007072 CHECK_GT(break_point_hit_count, 1);
Steve Blockd0582a62009-12-15 09:54:21 +00007073
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007074 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
7075 CheckDebuggerUnloaded(env->GetIsolate());
Steve Blockd0582a62009-12-15 09:54:21 +00007076}
7077
7078
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007079v8::Local<v8::Context> debugee_context;
7080v8::Local<v8::Context> debugger_context;
Steve Blockd0582a62009-12-15 09:54:21 +00007081
7082
7083// Property getter that checks that current and calling contexts
7084// are both the debugee contexts.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007085static void NamedGetterWithCallingContextCheck(
Steve Blockd0582a62009-12-15 09:54:21 +00007086 v8::Local<v8::String> name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007087 const v8::PropertyCallbackInfo<v8::Value>& info) {
7088 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(name), "a"));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007089 v8::Local<v8::Context> current = info.GetIsolate()->GetCurrentContext();
Steve Blockd0582a62009-12-15 09:54:21 +00007090 CHECK(current == debugee_context);
7091 CHECK(current != debugger_context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007092 info.GetReturnValue().Set(1);
Steve Blockd0582a62009-12-15 09:54:21 +00007093}
7094
7095
7096// Debug event listener that checks if the first argument of a function is
7097// an object with property 'a' == 1. If the property has custom accessor
7098// this handler will eventually invoke it.
7099static void DebugEventGetAtgumentPropertyValue(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007100 const v8::Debug::EventDetails& event_details) {
7101 v8::DebugEvent event = event_details.GetEvent();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007102 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
Steve Blockd0582a62009-12-15 09:54:21 +00007103 if (event == v8::Break) {
7104 break_point_hit_count++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007105 CHECK(debugger_context == CcTest::isolate()->GetCurrentContext());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007106 v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(CompileRun(
Steve Blockd0582a62009-12-15 09:54:21 +00007107 "(function(exec_state) {\n"
7108 " return (exec_state.frame(0).argumentValue(0).property('a').\n"
7109 " value().value() == 1);\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007110 "})"));
Steve Blockd0582a62009-12-15 09:54:21 +00007111 const int argc = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007112 v8::Local<v8::Value> argv[argc] = {exec_state};
7113 v8::Local<v8::Value> result =
7114 func->Call(debugger_context, exec_state, argc, argv).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00007115 CHECK(result->IsTrue());
7116 }
7117}
7118
7119
7120TEST(CallingContextIsNotDebugContext) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007121 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
Steve Blockd0582a62009-12-15 09:54:21 +00007122 // Create and enter a debugee context.
Steve Blockd0582a62009-12-15 09:54:21 +00007123 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007124 v8::Isolate* isolate = env->GetIsolate();
7125 v8::HandleScope scope(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +00007126 env.ExposeDebug();
7127
7128 // Save handles to the debugger and debugee contexts to be used in
7129 // NamedGetterWithCallingContextCheck.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007130 debugee_context = env.context();
Steve Block44f0eee2011-05-26 01:26:41 +01007131 debugger_context = v8::Utils::ToLocal(debug->debug_context());
Steve Blockd0582a62009-12-15 09:54:21 +00007132
7133 // Create object with 'a' property accessor.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007134 v8::Local<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
7135 named->SetAccessor(v8_str(isolate, "a"), NamedGetterWithCallingContextCheck);
7136 CHECK(env->Global()
7137 ->Set(debugee_context, v8_str(isolate, "obj"),
7138 named->NewInstance(debugee_context).ToLocalChecked())
7139 .FromJust());
Steve Blockd0582a62009-12-15 09:54:21 +00007140
7141 // Register the debug event listener
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007142 v8::Debug::SetDebugEventListener(isolate, DebugEventGetAtgumentPropertyValue);
Steve Blockd0582a62009-12-15 09:54:21 +00007143
7144 // Create a function that invokes debugger.
7145 v8::Local<v8::Function> foo = CompileFunction(
7146 &env,
7147 "function bar(x) { debugger; }"
7148 "function foo(){ bar(obj); }",
7149 "foo");
7150
7151 break_point_hit_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007152 foo->Call(debugee_context, env->Global(), 0, NULL).ToLocalChecked();
Steve Blockd0582a62009-12-15 09:54:21 +00007153 CHECK_EQ(1, break_point_hit_count);
7154
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007155 v8::Debug::SetDebugEventListener(isolate, nullptr);
7156 debugee_context = v8::Local<v8::Context>();
7157 debugger_context = v8::Local<v8::Context>();
7158 CheckDebuggerUnloaded(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +00007159}
Steve Block6ded16b2010-05-10 14:33:55 +01007160
7161
7162TEST(DebugContextIsPreservedBetweenAccesses) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007163 v8::HandleScope scope(CcTest::isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007164 v8::Debug::SetDebugEventListener(CcTest::isolate(),
7165 DebugEventBreakPointHitCount);
7166 v8::Local<v8::Context> context1 =
7167 v8::Debug::GetDebugContext(CcTest::isolate());
7168 v8::Local<v8::Context> context2 =
7169 v8::Debug::GetDebugContext(CcTest::isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007170 CHECK(v8::Utils::OpenHandle(*context1).is_identical_to(
7171 v8::Utils::OpenHandle(*context2)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007172 v8::Debug::SetDebugEventListener(CcTest::isolate(), nullptr);
Leon Clarkef7060e22010-06-03 12:02:55 +01007173}
7174
7175
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007176TEST(NoDebugContextWhenDebuggerDisabled) {
7177 v8::HandleScope scope(CcTest::isolate());
7178 v8::Local<v8::Context> context =
7179 v8::Debug::GetDebugContext(CcTest::isolate());
7180 CHECK(context.IsEmpty());
7181}
7182
Ben Murdoch61f157c2016-09-16 13:49:30 +01007183static void DebugEventCheckContext(
7184 const v8::Debug::EventDetails& event_details) {
7185 if (event_details.GetEvent() == v8::Break) {
7186 v8::Isolate* isolate = event_details.GetIsolate();
7187 CHECK(v8::Debug::GetDebuggedContext(isolate)
7188 .ToLocalChecked()
7189 ->Global()
7190 ->Equals(isolate->GetCurrentContext(),
7191 event_details.GetEventContext()->Global())
7192 .FromJust());
7193 }
7194}
7195
7196static void CheckContext(const v8::FunctionCallbackInfo<v8::Value>& args) {
7197 CHECK(v8::Debug::GetDebuggedContext(args.GetIsolate()).IsEmpty());
7198}
7199
7200TEST(DebuggedContext) {
7201 DebugLocalContext env;
7202 v8::Isolate* isolate = env->GetIsolate();
7203
7204 v8::Debug::SetDebugEventListener(isolate, DebugEventCheckContext);
7205
7206 v8::Local<v8::Function> foo =
7207 CompileFunction(&env, "function foo(){bar=0;}", "foo");
7208
7209 SetBreakPoint(foo, 0);
7210 foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
7211
7212 v8::Local<v8::Function> fun = v8::FunctionTemplate::New(isolate, CheckContext)
7213 ->GetFunction(env.context())
7214 .ToLocalChecked();
7215 fun->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
7216}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007217
7218static v8::Local<v8::Value> expected_callback_data;
Leon Clarkef7060e22010-06-03 12:02:55 +01007219static void DebugEventContextChecker(const v8::Debug::EventDetails& details) {
7220 CHECK(details.GetEventContext() == expected_context);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007221 CHECK(expected_callback_data->Equals(details.GetEventContext(),
7222 details.GetCallbackData())
7223 .FromJust());
Leon Clarkef7060e22010-06-03 12:02:55 +01007224}
7225
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007226
Leon Clarkef7060e22010-06-03 12:02:55 +01007227// Check that event details contain context where debug event occured.
7228TEST(DebugEventContext) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007229 v8::Isolate* isolate = CcTest::isolate();
7230 v8::HandleScope scope(isolate);
7231 expected_context = v8::Context::New(isolate);
7232 expected_callback_data = v8::Int32::New(isolate, 2010);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007233 v8::Debug::SetDebugEventListener(isolate, DebugEventContextChecker,
7234 expected_callback_data);
Leon Clarkef7060e22010-06-03 12:02:55 +01007235 v8::Context::Scope context_scope(expected_context);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007236 v8::Script::Compile(expected_context,
7237 v8_str(isolate, "(function(){debugger;})();"))
7238 .ToLocalChecked()
7239 ->Run(expected_context)
7240 .ToLocalChecked();
Leon Clarkef7060e22010-06-03 12:02:55 +01007241 expected_context.Clear();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007242 v8::Debug::SetDebugEventListener(isolate, nullptr);
7243 expected_context_data = v8::Local<v8::Value>();
7244 CheckDebuggerUnloaded(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01007245}
Leon Clarkef7060e22010-06-03 12:02:55 +01007246
Ben Murdoch3bec4d22010-07-22 14:51:16 +01007247
Ben Murdochb0fe1622011-05-05 13:52:32 +01007248static bool debug_event_break_deoptimize_done = false;
7249
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007250static void DebugEventBreakDeoptimize(
7251 const v8::Debug::EventDetails& event_details) {
7252 v8::DebugEvent event = event_details.GetEvent();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007253 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
7254 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007255 if (event == v8::Break) {
7256 if (!frame_function_name.IsEmpty()) {
7257 // Get the name of the function.
7258 const int argc = 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007259 v8::Local<v8::Value> argv[argc] = {
7260 exec_state, v8::Integer::New(CcTest::isolate(), 0)};
7261 v8::Local<v8::Value> result =
7262 frame_function_name->Call(context, exec_state, argc, argv)
7263 .ToLocalChecked();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007264 if (!result->IsUndefined()) {
7265 char fn[80];
7266 CHECK(result->IsString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007267 v8::Local<v8::String> function_name(
7268 result->ToString(context).ToLocalChecked());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007269 function_name->WriteUtf8(fn);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007270 if (strcmp(fn, "bar") == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007271 i::Deoptimizer::DeoptimizeAll(CcTest::i_isolate());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007272 debug_event_break_deoptimize_done = true;
7273 }
7274 }
7275 }
7276
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007277 v8::Debug::DebugBreak(CcTest::isolate());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007278 }
7279}
7280
7281
7282// Test deoptimization when execution is broken using the debug break stack
7283// check interrupt.
7284TEST(DeoptimizeDuringDebugBreak) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007285 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007286 v8::HandleScope scope(env->GetIsolate());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007287 env.ExposeDebug();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007288 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007289
7290 // Create a function for checking the function when hitting a break point.
7291 frame_function_name = CompileFunction(&env,
7292 frame_function_name_source,
7293 "frame_function_name");
7294
Ben Murdochb0fe1622011-05-05 13:52:32 +01007295 // Set a debug event listener which will keep interrupting execution until
7296 // debug break. When inside function bar it will deoptimize all functions.
7297 // This tests lazy deoptimization bailout for the stack check, as the first
7298 // time in function bar when using debug break and no break points will be at
7299 // the initial stack check.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007300 v8::Debug::SetDebugEventListener(env->GetIsolate(),
7301 DebugEventBreakDeoptimize);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007302
7303 // Compile and run function bar which will optimize it for some flag settings.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007304 v8::Local<v8::Function> f = CompileFunction(&env, "function bar(){}", "bar");
7305 f->Call(context, v8::Undefined(env->GetIsolate()), 0, NULL).ToLocalChecked();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007306
7307 // Set debug break and call bar again.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007308 v8::Debug::DebugBreak(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007309 f->Call(context, v8::Undefined(env->GetIsolate()), 0, NULL).ToLocalChecked();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007310
7311 CHECK(debug_event_break_deoptimize_done);
7312
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007313 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007314}
7315
7316
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007317static void DebugEventBreakWithOptimizedStack(
7318 const v8::Debug::EventDetails& event_details) {
7319 v8::Isolate* isolate = event_details.GetEventContext()->GetIsolate();
7320 v8::DebugEvent event = event_details.GetEvent();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007321 v8::Local<v8::Object> exec_state = event_details.GetExecutionState();
7322 v8::Local<v8::Context> context = isolate->GetCurrentContext();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007323 if (event == v8::Break) {
7324 if (!frame_function_name.IsEmpty()) {
7325 for (int i = 0; i < 2; i++) {
7326 const int argc = 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007327 v8::Local<v8::Value> argv[argc] = {exec_state,
7328 v8::Integer::New(isolate, i)};
Ben Murdochb0fe1622011-05-05 13:52:32 +01007329 // Get the name of the function in frame i.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007330 v8::Local<v8::Value> result =
7331 frame_function_name->Call(context, exec_state, argc, argv)
7332 .ToLocalChecked();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007333 CHECK(result->IsString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007334 v8::Local<v8::String> function_name(
7335 result->ToString(context).ToLocalChecked());
7336 CHECK(
7337 function_name->Equals(context, v8_str(isolate, "loop")).FromJust());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007338 // Get the name of the first argument in frame i.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007339 result = frame_argument_name->Call(context, exec_state, argc, argv)
7340 .ToLocalChecked();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007341 CHECK(result->IsString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007342 v8::Local<v8::String> argument_name(
7343 result->ToString(context).ToLocalChecked());
7344 CHECK(argument_name->Equals(context, v8_str(isolate, "count"))
7345 .FromJust());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007346 // Get the value of the first argument in frame i. If the
Ben Murdoch097c5b22016-05-18 11:27:45 +01007347 // function is optimized the value will be undefined, otherwise
Ben Murdochb0fe1622011-05-05 13:52:32 +01007348 // the value will be '1 - i'.
7349 //
7350 // TODO(3141533): We should be able to get the real value for
7351 // optimized frames.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007352 result = frame_argument_value->Call(context, exec_state, argc, argv)
7353 .ToLocalChecked();
7354 CHECK(result->IsUndefined() ||
7355 (result->Int32Value(context).FromJust() == 1 - i));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007356 // Get the name of the first local variable.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007357 result = frame_local_name->Call(context, exec_state, argc, argv)
7358 .ToLocalChecked();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007359 CHECK(result->IsString());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007360 v8::Local<v8::String> local_name(
7361 result->ToString(context).ToLocalChecked());
7362 CHECK(local_name->Equals(context, v8_str(isolate, "local")).FromJust());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007363 // Get the value of the first local variable. If the function
7364 // is optimized the value will be undefined, otherwise it will
7365 // be 42.
7366 //
7367 // TODO(3141533): We should be able to get the real value for
7368 // optimized frames.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007369 result = frame_local_value->Call(context, exec_state, argc, argv)
7370 .ToLocalChecked();
7371 CHECK(result->IsUndefined() ||
7372 (result->Int32Value(context).FromJust() == 42));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007373 }
7374 }
7375 }
7376}
7377
7378
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007379static void ScheduleBreak(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007380 v8::Debug::SetDebugEventListener(args.GetIsolate(),
7381 DebugEventBreakWithOptimizedStack);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007382 v8::Debug::DebugBreak(args.GetIsolate());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007383}
7384
7385
7386TEST(DebugBreakStackInspection) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007387 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007388 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007389 v8::Local<v8::Context> context = env.context();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007390
7391 frame_function_name =
7392 CompileFunction(&env, frame_function_name_source, "frame_function_name");
7393 frame_argument_name =
7394 CompileFunction(&env, frame_argument_name_source, "frame_argument_name");
7395 frame_argument_value = CompileFunction(&env,
7396 frame_argument_value_source,
7397 "frame_argument_value");
7398 frame_local_name =
7399 CompileFunction(&env, frame_local_name_source, "frame_local_name");
7400 frame_local_value =
7401 CompileFunction(&env, frame_local_value_source, "frame_local_value");
7402
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007403 v8::Local<v8::FunctionTemplate> schedule_break_template =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007404 v8::FunctionTemplate::New(env->GetIsolate(), ScheduleBreak);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007405 v8::Local<v8::Function> schedule_break =
7406 schedule_break_template->GetFunction(context).ToLocalChecked();
7407 CHECK(env->Global()
7408 ->Set(context, v8_str("scheduleBreak"), schedule_break)
7409 .FromJust());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007410
7411 const char* src =
7412 "function loop(count) {"
7413 " var local = 42;"
7414 " if (count < 1) { scheduleBreak(); loop(count + 1); }"
7415 "}"
7416 "loop(0);";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007417 v8::Script::Compile(context, v8_str(env->GetIsolate(), src))
7418 .ToLocalChecked()
7419 ->Run(context)
7420 .ToLocalChecked();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007421}
7422
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007423
7424// Test that setting the terminate execution flag during debug break processing.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007425static void TestDebugBreakInLoop(const char* loop_head,
7426 const char** loop_bodies,
7427 const char* loop_tail) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007428 // Receive 10 breaks for each test and then terminate JavaScript execution.
7429 static const int kBreaksPerTest = 10;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007430
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007431 for (int i = 0; loop_bodies[i] != NULL; i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007432 // Perform a lazy deoptimization after various numbers of breaks
7433 // have been hit.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007434
7435 EmbeddedVector<char, 1024> buffer;
7436 SNPrintF(buffer, "function f() {%s%s%s}", loop_head, loop_bodies[i],
7437 loop_tail);
7438
7439 i::PrintF("%s\n", buffer.start());
7440
7441 for (int j = 0; j < 3; j++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007442 break_point_hit_count_deoptimize = j;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007443 if (j == 2) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007444 break_point_hit_count_deoptimize = kBreaksPerTest;
7445 }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007446
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007447 break_point_hit_count = 0;
7448 max_break_point_hit_count = kBreaksPerTest;
7449 terminate_after_max_break_point_hit = true;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007450
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007451 // Function with infinite loop.
7452 CompileRun(buffer.start());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007453
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007454 // Set the debug break to enter the debugger as soon as possible.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007455 v8::Debug::DebugBreak(CcTest::isolate());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007456
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007457 // Call function with infinite loop.
7458 CompileRun("f();");
7459 CHECK_EQ(kBreaksPerTest, break_point_hit_count);
7460
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007461 CHECK(!CcTest::isolate()->IsExecutionTerminating());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007462 }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007463 }
7464}
7465
7466
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007467static const char* loop_bodies_1[] = {"",
7468 "g()",
7469 "if (a == 0) { g() }",
7470 "if (a == 1) { g() }",
7471 "if (a == 0) { g() } else { h() }",
7472 "if (a == 0) { continue }",
7473 NULL};
7474
7475
7476static const char* loop_bodies_2[] = {
7477 "if (a == 1) { continue }",
7478 "switch (a) { case 1: g(); }",
7479 "switch (a) { case 1: continue; }",
7480 "switch (a) { case 1: g(); break; default: h() }",
7481 "switch (a) { case 1: continue; break; default: h() }",
7482 NULL};
7483
7484
7485void DebugBreakLoop(const char* loop_header, const char** loop_bodies,
7486 const char* loop_footer) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007487 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007488 v8::HandleScope scope(env->GetIsolate());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007489
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007490 // Register a debug event listener which sets the break flag and counts.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007491 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventBreakMax);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007492
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007493 CompileRun(
7494 "var a = 1;\n"
7495 "function g() { }\n"
7496 "function h() { }");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007497
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007498 TestDebugBreakInLoop(loop_header, loop_bodies, loop_footer);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007499
7500 // Get rid of the debug event listener.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007501 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
7502 CheckDebuggerUnloaded(env->GetIsolate());
7503}
7504
7505
7506TEST(DebugBreakInWhileTrue1) {
7507 DebugBreakLoop("while (true) {", loop_bodies_1, "}");
7508}
7509
7510
7511TEST(DebugBreakInWhileTrue2) {
7512 DebugBreakLoop("while (true) {", loop_bodies_2, "}");
7513}
7514
7515
7516TEST(DebugBreakInWhileCondition1) {
7517 DebugBreakLoop("while (a == 1) {", loop_bodies_1, "}");
7518}
7519
7520
7521TEST(DebugBreakInWhileCondition2) {
7522 DebugBreakLoop("while (a == 1) {", loop_bodies_2, "}");
7523}
7524
7525
7526TEST(DebugBreakInDoWhileTrue1) {
7527 DebugBreakLoop("do {", loop_bodies_1, "} while (true)");
7528}
7529
7530
7531TEST(DebugBreakInDoWhileTrue2) {
7532 DebugBreakLoop("do {", loop_bodies_2, "} while (true)");
7533}
7534
7535
7536TEST(DebugBreakInDoWhileCondition1) {
7537 DebugBreakLoop("do {", loop_bodies_1, "} while (a == 1)");
7538}
7539
7540
7541TEST(DebugBreakInDoWhileCondition2) {
7542 DebugBreakLoop("do {", loop_bodies_2, "} while (a == 1)");
7543}
7544
7545
7546TEST(DebugBreakInFor1) { DebugBreakLoop("for (;;) {", loop_bodies_1, "}"); }
7547
7548
7549TEST(DebugBreakInFor2) { DebugBreakLoop("for (;;) {", loop_bodies_2, "}"); }
7550
7551
7552TEST(DebugBreakInForCondition1) {
7553 DebugBreakLoop("for (;a == 1;) {", loop_bodies_1, "}");
7554}
7555
7556
7557TEST(DebugBreakInForCondition2) {
7558 DebugBreakLoop("for (;a == 1;) {", loop_bodies_2, "}");
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007559}
7560
7561
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007562v8::Local<v8::Script> inline_script;
7563
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007564static void DebugBreakInlineListener(
7565 const v8::Debug::EventDetails& event_details) {
7566 v8::DebugEvent event = event_details.GetEvent();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007567 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007568 if (event != v8::Break) return;
7569
7570 int expected_frame_count = 4;
7571 int expected_line_number[] = {1, 4, 7, 12};
7572
7573 i::Handle<i::Object> compiled_script = v8::Utils::OpenHandle(*inline_script);
7574 i::Handle<i::Script> source_script = i::Handle<i::Script>(i::Script::cast(
7575 i::JSFunction::cast(*compiled_script)->shared()->script()));
7576
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007577 int break_id = CcTest::i_isolate()->debug()->break_id();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007578 char script[128];
7579 i::Vector<char> script_vector(script, sizeof(script));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007580 SNPrintF(script_vector, "%%GetFrameCount(%d)", break_id);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007581 v8::Local<v8::Value> result = CompileRun(script);
7582
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007583 int frame_count = result->Int32Value(context).FromJust();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007584 CHECK_EQ(expected_frame_count, frame_count);
7585
7586 for (int i = 0; i < frame_count; i++) {
7587 // The 5. element in the returned array of GetFrameDetails contains the
7588 // source position of that frame.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007589 SNPrintF(script_vector, "%%GetFrameDetails(%d, %d)[5]", break_id, i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007590 v8::Local<v8::Value> result = CompileRun(script);
7591 CHECK_EQ(expected_line_number[i],
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007592 i::Script::GetLineNumber(source_script,
7593 result->Int32Value(context).FromJust()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007594 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007595 v8::Debug::SetDebugEventListener(CcTest::isolate(), nullptr);
7596 CcTest::isolate()->TerminateExecution();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007597}
7598
7599
7600TEST(DebugBreakInline) {
7601 i::FLAG_allow_natives_syntax = true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007602 DebugLocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007603 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007604 v8::Local<v8::Context> context = env.context();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007605 const char* source =
7606 "function debug(b) { \n"
7607 " if (b) debugger; \n"
7608 "} \n"
7609 "function f(b) { \n"
7610 " debug(b) \n"
7611 "}; \n"
7612 "function g(b) { \n"
7613 " f(b); \n"
7614 "}; \n"
7615 "g(false); \n"
7616 "g(false); \n"
7617 "%OptimizeFunctionOnNextCall(g); \n"
7618 "g(true);";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007619 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugBreakInlineListener);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007620 inline_script =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007621 v8::Script::Compile(context, v8_str(env->GetIsolate(), source))
7622 .ToLocalChecked();
7623 inline_script->Run(context).ToLocalChecked();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007624}
7625
7626
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007627static void DebugEventStepNext(
7628 const v8::Debug::EventDetails& event_details) {
7629 v8::DebugEvent event = event_details.GetEvent();
7630 if (event == v8::Break) {
7631 PrepareStep(StepNext);
7632 }
7633}
7634
7635
7636static void RunScriptInANewCFrame(const char* source) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007637 v8::TryCatch try_catch(CcTest::isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007638 CompileRun(source);
7639 CHECK(try_catch.HasCaught());
7640}
7641
7642
7643TEST(Regress131642) {
7644 // Bug description:
7645 // When doing StepNext through the first script, the debugger is not reset
7646 // after exiting through exception. A flawed implementation enabling the
7647 // debugger to step into Array.prototype.forEach breaks inside the callback
7648 // for forEach in the second script under the assumption that we are in a
7649 // recursive call. In an attempt to step out, we crawl the stack using the
7650 // recorded frame pointer from the first script and fail when not finding it
7651 // on the stack.
7652 DebugLocalContext env;
7653 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007654 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugEventStepNext);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007655
7656 // We step through the first script. It exits through an exception. We run
7657 // this inside a new frame to record a different FP than the second script
7658 // would expect.
7659 const char* script_1 = "debugger; throw new Error();";
7660 RunScriptInANewCFrame(script_1);
7661
7662 // The second script uses forEach.
7663 const char* script_2 = "[0].forEach(function() { });";
7664 CompileRun(script_2);
7665
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007666 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007667}
7668
7669
7670// Import from test-heap.cc
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007671namespace v8 {
7672namespace internal {
7673
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007674int CountNativeContexts();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007675}
7676}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007677
7678
7679static void NopListener(const v8::Debug::EventDetails& event_details) {
7680}
7681
7682
7683TEST(DebuggerCreatesContextIffActive) {
7684 DebugLocalContext env;
7685 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007686 CHECK_EQ(1, v8::internal::CountNativeContexts());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007687
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007688 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007689 CompileRun("debugger;");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007690 CHECK_EQ(1, v8::internal::CountNativeContexts());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007691
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007692 v8::Debug::SetDebugEventListener(env->GetIsolate(), NopListener);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007693 CompileRun("debugger;");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007694 CHECK_EQ(2, v8::internal::CountNativeContexts());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007695
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007696 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007697}
7698
7699
7700TEST(LiveEditEnabled) {
7701 v8::internal::FLAG_allow_natives_syntax = true;
7702 LocalContext env;
7703 v8::HandleScope scope(env->GetIsolate());
7704 v8::Debug::SetLiveEditEnabled(env->GetIsolate(), true);
7705 CompileRun("%LiveEditCompareStrings('', '')");
7706}
7707
7708
7709TEST(LiveEditDisabled) {
7710 v8::internal::FLAG_allow_natives_syntax = true;
7711 LocalContext env;
7712 v8::HandleScope scope(env->GetIsolate());
7713 v8::Debug::SetLiveEditEnabled(env->GetIsolate(), false);
7714 CompileRun("%LiveEditCompareStrings('', '')");
7715}
7716
7717
7718TEST(PrecompiledFunction) {
7719 // Regression test for crbug.com/346207. If we have preparse data, parsing the
7720 // function in the presence of the debugger (and breakpoints) should still
7721 // succeed. The bug was that preparsing was done lazily and parsing was done
7722 // eagerly, so, the symbol streams didn't match.
7723 DebugLocalContext env;
7724 v8::HandleScope scope(env->GetIsolate());
7725 env.ExposeDebug();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007726 v8::Debug::SetDebugEventListener(env->GetIsolate(), DebugBreakInlineListener);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007727
7728 v8::Local<v8::Function> break_here =
7729 CompileFunction(&env, "function break_here(){}", "break_here");
7730 SetBreakPoint(break_here, 0);
7731
7732 const char* source =
7733 "var a = b = c = 1; \n"
7734 "function this_is_lazy() { \n"
7735 // This symbol won't appear in the preparse data.
7736 " var a; \n"
7737 "} \n"
7738 "function bar() { \n"
7739 " return \"bar\"; \n"
7740 "}; \n"
7741 "a = b = c = 2; \n"
7742 "bar(); \n";
7743 v8::Local<v8::Value> result = ParserCacheCompileRun(source);
7744 CHECK(result->IsString());
7745 v8::String::Utf8Value utf8(result);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007746 CHECK_EQ(0, strcmp("bar", *utf8));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007747
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007748 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
7749 CheckDebuggerUnloaded(env->GetIsolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007750}
7751
7752
7753static void DebugBreakStackTraceListener(
7754 const v8::Debug::EventDetails& event_details) {
7755 v8::StackTrace::CurrentStackTrace(CcTest::isolate(), 10);
7756}
7757
7758
7759static void AddDebugBreak(const v8::FunctionCallbackInfo<v8::Value>& args) {
7760 v8::Debug::DebugBreak(args.GetIsolate());
7761}
7762
7763
7764TEST(DebugBreakStackTrace) {
7765 DebugLocalContext env;
7766 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007767 v8::Debug::SetDebugEventListener(env->GetIsolate(),
7768 DebugBreakStackTraceListener);
7769 v8::Local<v8::Context> context = env.context();
7770 v8::Local<v8::FunctionTemplate> add_debug_break_template =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007771 v8::FunctionTemplate::New(env->GetIsolate(), AddDebugBreak);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007772 v8::Local<v8::Function> add_debug_break =
7773 add_debug_break_template->GetFunction(context).ToLocalChecked();
7774 CHECK(env->Global()
7775 ->Set(context, v8_str("add_debug_break"), add_debug_break)
7776 .FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007777
7778 CompileRun("(function loop() {"
7779 " for (var j = 0; j < 1000; j++) {"
7780 " for (var i = 0; i < 1000; i++) {"
7781 " if (i == 999) add_debug_break();"
7782 " }"
7783 " }"
7784 "})()");
7785}
7786
7787
7788v8::base::Semaphore terminate_requested_semaphore(0);
7789v8::base::Semaphore terminate_fired_semaphore(0);
7790bool terminate_already_fired = false;
7791
7792
7793static void DebugBreakTriggerTerminate(
7794 const v8::Debug::EventDetails& event_details) {
7795 if (event_details.GetEvent() != v8::Break || terminate_already_fired) return;
7796 terminate_requested_semaphore.Signal();
7797 // Wait for at most 2 seconds for the terminate request.
7798 CHECK(terminate_fired_semaphore.WaitFor(v8::base::TimeDelta::FromSeconds(2)));
7799 terminate_already_fired = true;
7800}
7801
7802
7803class TerminationThread : public v8::base::Thread {
7804 public:
7805 explicit TerminationThread(v8::Isolate* isolate)
7806 : Thread(Options("terminator")), isolate_(isolate) {}
7807
7808 virtual void Run() {
7809 terminate_requested_semaphore.Wait();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007810 isolate_->TerminateExecution();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007811 terminate_fired_semaphore.Signal();
7812 }
7813
7814 private:
7815 v8::Isolate* isolate_;
7816};
7817
7818
7819TEST(DebugBreakOffThreadTerminate) {
7820 DebugLocalContext env;
7821 v8::Isolate* isolate = env->GetIsolate();
7822 v8::HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007823 v8::Debug::SetDebugEventListener(isolate, DebugBreakTriggerTerminate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007824 TerminationThread terminator(isolate);
7825 terminator.Start();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007826 v8::TryCatch try_catch(env->GetIsolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007827 v8::Debug::DebugBreak(isolate);
7828 CompileRun("while (true);");
7829 CHECK(try_catch.HasTerminated());
7830}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007831
7832
7833static void DebugEventExpectNoException(
7834 const v8::Debug::EventDetails& event_details) {
7835 v8::DebugEvent event = event_details.GetEvent();
7836 CHECK_NE(v8::Exception, event);
7837}
7838
7839
7840static void TryCatchWrappedThrowCallback(
7841 const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007842 v8::TryCatch try_catch(args.GetIsolate());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007843 CompileRun("throw 'rejection';");
7844 CHECK(try_catch.HasCaught());
7845}
7846
7847
7848TEST(DebugPromiseInterceptedByTryCatch) {
7849 DebugLocalContext env;
7850 v8::Isolate* isolate = env->GetIsolate();
7851 v8::HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007852 v8::Debug::SetDebugEventListener(isolate, &DebugEventExpectNoException);
7853 v8::Local<v8::Context> context = env.context();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007854 ChangeBreakOnException(false, true);
7855
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007856 v8::Local<v8::FunctionTemplate> fun =
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007857 v8::FunctionTemplate::New(isolate, TryCatchWrappedThrowCallback);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007858 CHECK(env->Global()
7859 ->Set(context, v8_str("fun"),
7860 fun->GetFunction(context).ToLocalChecked())
7861 .FromJust());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007862
7863 CompileRun("var p = new Promise(function(res, rej) { fun(); res(); });");
7864 CompileRun(
7865 "var r;"
Ben Murdochc5610432016-08-08 18:44:38 +01007866 "p.then(function() { r = 'resolved'; },"
7867 " function() { r = 'rejected'; });");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007868 CHECK(CompileRun("r")->Equals(context, v8_str("resolved")).FromJust());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007869}
7870
7871
7872static int exception_event_counter = 0;
7873
7874
7875static void DebugEventCountException(
7876 const v8::Debug::EventDetails& event_details) {
7877 v8::DebugEvent event = event_details.GetEvent();
7878 if (event == v8::Exception) exception_event_counter++;
7879}
7880
7881
7882static void ThrowCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
7883 CompileRun("throw 'rejection';");
7884}
7885
7886
7887TEST(DebugPromiseRejectedByCallback) {
7888 DebugLocalContext env;
7889 v8::Isolate* isolate = env->GetIsolate();
7890 v8::HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007891 v8::Debug::SetDebugEventListener(isolate, &DebugEventCountException);
7892 v8::Local<v8::Context> context = env.context();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007893 ChangeBreakOnException(false, true);
7894 exception_event_counter = 0;
7895
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007896 v8::Local<v8::FunctionTemplate> fun =
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007897 v8::FunctionTemplate::New(isolate, ThrowCallback);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007898 CHECK(env->Global()
7899 ->Set(context, v8_str("fun"),
7900 fun->GetFunction(context).ToLocalChecked())
7901 .FromJust());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007902
7903 CompileRun("var p = new Promise(function(res, rej) { fun(); res(); });");
7904 CompileRun(
7905 "var r;"
Ben Murdochc5610432016-08-08 18:44:38 +01007906 "p.then(function() { r = 'resolved'; },"
7907 " function(e) { r = 'rejected' + e; });");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007908 CHECK(
7909 CompileRun("r")->Equals(context, v8_str("rejectedrejection")).FromJust());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007910 CHECK_EQ(1, exception_event_counter);
7911}
7912
7913
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007914static void DebugHarmonyScopingListener(
7915 const v8::Debug::EventDetails& event_details) {
7916 v8::DebugEvent event = event_details.GetEvent();
7917 if (event != v8::Break) return;
7918
7919 int break_id = CcTest::i_isolate()->debug()->break_id();
7920
7921 char script[128];
7922 i::Vector<char> script_vector(script, sizeof(script));
7923 SNPrintF(script_vector, "%%GetFrameCount(%d)", break_id);
7924 ExpectInt32(script, 1);
7925
7926 SNPrintF(script_vector, "var frame = new FrameMirror(%d, 0);", break_id);
7927 CompileRun(script);
7928 ExpectInt32("frame.evaluate('x').value_", 1);
7929 ExpectInt32("frame.evaluate('y').value_", 2);
7930
7931 CompileRun("var allScopes = frame.allScopes()");
7932 ExpectInt32("allScopes.length", 2);
7933
7934 ExpectBoolean("allScopes[0].scopeType() === ScopeType.Script", true);
7935
7936 ExpectInt32("allScopes[0].scopeObject().value_.x", 1);
7937
7938 ExpectInt32("allScopes[0].scopeObject().value_.y", 2);
7939
7940 CompileRun("allScopes[0].setVariableValue('x', 5);");
7941 CompileRun("allScopes[0].setVariableValue('y', 6);");
7942 ExpectInt32("frame.evaluate('x + y').value_", 11);
7943}
7944
7945
7946TEST(DebugBreakInLexicalScopes) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007947 i::FLAG_allow_natives_syntax = true;
7948
7949 DebugLocalContext env;
7950 v8::Isolate* isolate = env->GetIsolate();
7951 v8::HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007952 v8::Debug::SetDebugEventListener(isolate, DebugHarmonyScopingListener);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007953
7954 CompileRun(
7955 "'use strict'; \n"
7956 "let x = 1; \n");
7957 ExpectInt32(
7958 "'use strict'; \n"
7959 "let y = 2; \n"
7960 "debugger; \n"
7961 "x * y",
7962 30);
7963 ExpectInt32(
7964 "x = 1; y = 2; \n"
7965 "debugger;"
7966 "x * y",
7967 30);
7968}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007969
7970static int after_compile_handler_depth = 0;
7971static void HandleInterrupt(v8::Isolate* isolate, void* data) {
7972 CHECK_EQ(0, after_compile_handler_depth);
7973}
7974
7975static void NoInterruptsOnDebugEvent(
7976 const v8::Debug::EventDetails& event_details) {
7977 if (event_details.GetEvent() != v8::AfterCompile) return;
7978 ++after_compile_handler_depth;
7979 // Do not allow nested AfterCompile events.
7980 CHECK(after_compile_handler_depth <= 1);
7981 v8::Isolate* isolate = event_details.GetEventContext()->GetIsolate();
7982 isolate->RequestInterrupt(&HandleInterrupt, nullptr);
7983 CompileRun("function foo() {}; foo();");
7984 --after_compile_handler_depth;
7985}
7986
7987
7988TEST(NoInterruptsInDebugListener) {
7989 DebugLocalContext env;
7990 v8::Debug::SetDebugEventListener(env->GetIsolate(), NoInterruptsOnDebugEvent);
7991 CompileRun("void(0);");
7992}
Ben Murdoch097c5b22016-05-18 11:27:45 +01007993
7994class TestBreakLocation : public i::BreakLocation {
7995 public:
7996 using i::BreakLocation::GetIterator;
7997 using i::BreakLocation::Iterator;
7998};
7999
8000TEST(BreakLocationIterator) {
8001 DebugLocalContext env;
8002 v8::Isolate* isolate = env->GetIsolate();
8003 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
8004 v8::HandleScope scope(isolate);
8005
8006 v8::Local<v8::Value> result = CompileRun(
8007 "function f() {\n"
8008 " debugger; \n"
8009 " f(); \n"
8010 " debugger; \n"
8011 "} \n"
8012 "f");
8013 Handle<i::Object> function_obj = v8::Utils::OpenHandle(*result);
8014 Handle<i::JSFunction> function = Handle<i::JSFunction>::cast(function_obj);
8015 Handle<i::SharedFunctionInfo> shared(function->shared());
8016
8017 EnableDebugger(isolate);
8018 CHECK(i_isolate->debug()->EnsureDebugInfo(shared, function));
8019
8020 Handle<i::DebugInfo> debug_info(shared->GetDebugInfo());
8021 int code_size = debug_info->abstract_code()->Size();
8022
8023 bool found_return = false;
8024 bool found_call = false;
8025 bool found_debugger = false;
8026
8027 // Test public interface.
8028 for (int i = 0; i < code_size; i++) {
8029 i::BreakLocation location = i::BreakLocation::FromCodeOffset(debug_info, i);
8030 if (location.IsCall()) found_call = true;
8031 if (location.IsReturn()) found_return = true;
8032 if (location.IsDebuggerStatement()) found_debugger = true;
8033 }
8034 CHECK(found_call);
8035 CHECK(found_return);
8036 CHECK(found_debugger);
8037
8038 // Test underlying implementation.
8039 TestBreakLocation::Iterator* iterator =
8040 TestBreakLocation::GetIterator(debug_info, i::ALL_BREAK_LOCATIONS);
8041 CHECK(iterator->GetBreakLocation().IsDebuggerStatement());
8042 CHECK_EQ(7, iterator->GetBreakLocation().position());
8043 iterator->Next();
8044 CHECK(iterator->GetBreakLocation().IsDebugBreakSlot());
8045 CHECK_EQ(22, iterator->GetBreakLocation().position());
8046 iterator->Next();
8047 CHECK(iterator->GetBreakLocation().IsCall());
8048 CHECK_EQ(22, iterator->GetBreakLocation().position());
8049 iterator->Next();
8050 CHECK(iterator->GetBreakLocation().IsDebuggerStatement());
8051 CHECK_EQ(37, iterator->GetBreakLocation().position());
8052 iterator->Next();
8053 CHECK(iterator->GetBreakLocation().IsReturn());
8054 CHECK_EQ(50, iterator->GetBreakLocation().position());
8055 iterator->Next();
8056 CHECK(iterator->Done());
8057 delete iterator;
8058
8059 iterator = TestBreakLocation::GetIterator(debug_info, i::CALLS_AND_RETURNS);
8060 CHECK(iterator->GetBreakLocation().IsCall());
8061 CHECK_EQ(22, iterator->GetBreakLocation().position());
8062 iterator->Next();
8063 CHECK(iterator->GetBreakLocation().IsReturn());
8064 CHECK_EQ(50, iterator->GetBreakLocation().position());
8065 iterator->Next();
8066 CHECK(iterator->Done());
8067 delete iterator;
8068
8069 DisableDebugger(isolate);
8070}
Ben Murdochda12d292016-06-02 14:46:10 +01008071
8072TEST(DisableTailCallElimination) {
8073 i::FLAG_allow_natives_syntax = true;
8074 i::FLAG_harmony_tailcalls = true;
8075 // TODO(ishell, 4698): Investigate why TurboFan in --always-opt mode makes
8076 // stack[2].getFunctionName() return null.
8077 i::FLAG_turbo_inlining = false;
8078
8079 DebugLocalContext env;
8080 v8::Isolate* isolate = env->GetIsolate();
8081 v8::HandleScope scope(isolate);
8082 CHECK(v8::Debug::IsTailCallEliminationEnabled(isolate));
8083
8084 CompileRun(
8085 "'use strict'; \n"
8086 "Error.prepareStackTrace = (error,stack) => { \n"
8087 " error.strace = stack; \n"
8088 " return error.message + \"\\n at \" + stack.join(\"\\n at \"); \n"
8089 "} \n"
8090 " \n"
8091 "function getCaller() { \n"
8092 " var e = new Error(); \n"
8093 " e.stack; // prepare stack trace \n"
8094 " var stack = e.strace; \n"
8095 " %GlobalPrint('caller: '); \n"
8096 " %GlobalPrint(stack[2].getFunctionName()); \n"
8097 " %GlobalPrint('\\n'); \n"
8098 " return stack[2].getFunctionName(); \n"
8099 "} \n"
8100 "function f() { \n"
8101 " var caller = getCaller(); \n"
8102 " if (caller === 'g') return 1; \n"
8103 " if (caller === 'h') return 2; \n"
8104 " return 0; \n"
8105 "} \n"
8106 "function g() { \n"
8107 " return f(); \n"
8108 "} \n"
8109 "function h() { \n"
8110 " var result = g(); \n"
8111 " return result; \n"
8112 "} \n"
8113 "%NeverOptimizeFunction(getCaller); \n"
8114 "%NeverOptimizeFunction(f); \n"
8115 "%NeverOptimizeFunction(h); \n"
8116 "");
8117 ExpectInt32("h();", 2);
8118 ExpectInt32("h(); %OptimizeFunctionOnNextCall(g); h();", 2);
8119 v8::Debug::SetTailCallEliminationEnabled(isolate, false);
8120 CHECK(!v8::Debug::IsTailCallEliminationEnabled(isolate));
8121 ExpectInt32("h();", 1);
8122 ExpectInt32("h(); %OptimizeFunctionOnNextCall(g); h();", 1);
8123 v8::Debug::SetTailCallEliminationEnabled(isolate, true);
8124 CHECK(v8::Debug::IsTailCallEliminationEnabled(isolate));
8125 ExpectInt32("h();", 2);
8126 ExpectInt32("h(); %OptimizeFunctionOnNextCall(g); h();", 2);
8127}
8128
8129TEST(DebugStepNextTailCallEliminiation) {
8130 i::FLAG_allow_natives_syntax = true;
8131 i::FLAG_harmony_tailcalls = true;
8132 // TODO(ishell, 4698): Investigate why TurboFan in --always-opt mode makes
8133 // stack[2].getFunctionName() return null.
8134 i::FLAG_turbo_inlining = false;
8135
8136 DebugLocalContext env;
8137 env.ExposeDebug();
8138 v8::Isolate* isolate = env->GetIsolate();
8139 v8::HandleScope scope(isolate);
8140 CHECK(v8::Debug::IsTailCallEliminationEnabled(isolate));
8141
8142 const char* source =
8143 "'use strict'; \n"
8144 "var Debug = debug.Debug; \n"
8145 "var exception = null; \n"
8146 "var breaks = 0; \n"
8147 "var log = []; \n"
8148 "function f(x) { \n"
8149 " if (x == 2) { \n"
8150 " debugger; // Break a \n"
8151 " } \n"
8152 " if (x-- > 0) { // Break b \n"
8153 " return f(x); // Break c \n"
8154 " } \n"
8155 "} // Break e \n"
8156 "function listener(event, exec_state, event_data, data) {\n"
8157 " if (event != Debug.DebugEvent.Break) return; \n"
8158 " try { \n"
8159 " var line = exec_state.frame(0).sourceLineText(); \n"
8160 " var col = exec_state.frame(0).sourceColumn(); \n"
8161 " var match = line.match(/\\/\\/ Break (\\w)/); \n"
8162 " log.push(match[1] + col); \n"
8163 " exec_state.prepareStep(Debug.StepAction.StepNext); \n"
8164 " } catch (e) { \n"
8165 " exception = e; \n"
8166 " }; \n"
8167 "}; \n"
8168 "Debug.setListener(listener); \n"
8169 "f(4); \n"
8170 "Debug.setListener(null); // Break d \n";
8171
8172 CompileRun(source);
8173 ExpectNull("exception");
8174 ExpectString("JSON.stringify(log)", "[\"a4\",\"b2\",\"c4\",\"c11\",\"d0\"]");
8175
8176 v8::Debug::SetTailCallEliminationEnabled(isolate, false);
8177 CompileRun(
8178 "log = []; \n"
8179 "Debug.setListener(listener); \n"
8180 "f(5); \n"
8181 "Debug.setListener(null); // Break f \n");
8182 ExpectNull("exception");
8183 ExpectString("JSON.stringify(log)",
8184 "[\"a4\",\"b2\",\"c4\",\"e0\",\"e0\",\"e0\",\"e0\",\"f0\"]");
8185}
Ben Murdochc5610432016-08-08 18:44:38 +01008186
8187size_t current_action = 0;
8188StepAction actions[] = {StepNext, StepNext};
8189static void DebugStepOverFunctionWithCaughtExceptionListener(
8190 const v8::Debug::EventDetails& event_details) {
8191 v8::DebugEvent event = event_details.GetEvent();
8192 if (event != v8::Break) return;
8193 ++break_point_hit_count;
8194 if (current_action >= 2) return;
8195 PrepareStep(actions[current_action]);
8196}
8197
8198TEST(DebugStepOverFunctionWithCaughtException) {
8199 i::FLAG_allow_natives_syntax = true;
8200
8201 DebugLocalContext env;
8202 v8::Isolate* isolate = env->GetIsolate();
8203 v8::HandleScope scope(isolate);
8204 v8::Debug::SetDebugEventListener(
8205 isolate, DebugStepOverFunctionWithCaughtExceptionListener);
8206
8207 break_point_hit_count = 0;
8208 CompileRun(
8209 "function foo() {\n"
8210 " try { throw new Error(); } catch (e) {}\n"
8211 "}\n"
8212 "debugger;\n"
8213 "foo();\n"
8214 "foo();\n");
8215
8216 v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr);
8217 CHECK_EQ(break_point_hit_count, 4);
8218}