OLD | NEW |
| (Empty) |
1 // Copyright 2011 the V8 project authors. All rights reserved. | |
2 // Redistribution and use in source and binary forms, with or without | |
3 // modification, are permitted provided that the following conditions are | |
4 // met: | |
5 // | |
6 // * Redistributions of source code must retain the above copyright | |
7 // notice, this list of conditions and the following disclaimer. | |
8 // * Redistributions in binary form must reproduce the above | |
9 // copyright notice, this list of conditions and the following | |
10 // disclaimer in the documentation and/or other materials provided | |
11 // with the distribution. | |
12 // * Neither the name of Google Inc. nor the names of its | |
13 // contributors may be used to endorse or promote products derived | |
14 // from this software without specific prior written permission. | |
15 // | |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | |
28 // Flags: --expose-debug-as debug --allow-natives-syntax --noanalyze-environment
-liveness | |
29 // The functions used for testing backtraces. They are at the top to make the | |
30 // testing of source line/column easier. | |
31 | |
32 "use strict"; | |
33 | |
34 // Get the Debug object exposed from the debug context global object. | |
35 var Debug = debug.Debug; | |
36 | |
37 var test_name; | |
38 var listener_delegate; | |
39 var listener_called; | |
40 var exception; | |
41 var begin_test_count = 0; | |
42 var end_test_count = 0; | |
43 var break_count = 0; | |
44 | |
45 | |
46 // Debug event listener which delegates. | |
47 function listener(event, exec_state, event_data, data) { | |
48 try { | |
49 if (event == Debug.DebugEvent.Break) { | |
50 break_count++; | |
51 listener_called = true; | |
52 listener_delegate(exec_state); | |
53 } | |
54 } catch (e) { | |
55 print(e, e.stack); | |
56 exception = e; | |
57 } | |
58 } | |
59 | |
60 // Add the debug event listener. | |
61 Debug.setListener(listener); | |
62 | |
63 | |
64 // Initialize for a new test. | |
65 function BeginTest(name) { | |
66 test_name = name; | |
67 listener_delegate = null; | |
68 listener_called = false; | |
69 exception = null; | |
70 begin_test_count++; | |
71 } | |
72 | |
73 | |
74 // Check result of a test. | |
75 function EndTest() { | |
76 assertTrue(listener_called, "listerner not called for " + test_name); | |
77 assertNull(exception, test_name, exception); | |
78 end_test_count++; | |
79 } | |
80 | |
81 var global_object = this; | |
82 | |
83 // Check that the scope chain contains the expected types of scopes. | |
84 function CheckScopeChain(scopes, exec_state) { | |
85 assertEquals(scopes.length, exec_state.frame().scopeCount()); | |
86 for (var i = 0; i < scopes.length; i++) { | |
87 var scope = exec_state.frame().scope(i); | |
88 assertTrue(scope.isScope()); | |
89 assertEquals(scopes[i], scope.scopeType()); | |
90 | |
91 // Check the global object when hitting the global scope. | |
92 if (scopes[i] == debug.ScopeType.Global) { | |
93 // Objects don't have same class (one is "global", other is "Object", | |
94 // so just check the properties directly. | |
95 assertPropertiesEqual(global_object, scope.scopeObject().value()); | |
96 } | |
97 } | |
98 } | |
99 | |
100 // Check that the content of the scope is as expected. For functions just check | |
101 // that there is a function. | |
102 function CheckScopeContent(content, number, exec_state) { | |
103 var scope = exec_state.frame().scope(number); | |
104 var count = 0; | |
105 for (var p in content) { | |
106 var property_mirror = scope.scopeObject().property(p); | |
107 if (property_mirror.isUndefined()) { | |
108 print('property ' + p + ' not found in scope'); | |
109 } | |
110 assertFalse(property_mirror.isUndefined(), | |
111 'property ' + p + ' not found in scope'); | |
112 if (typeof(content[p]) === 'function') { | |
113 assertTrue(property_mirror.value().isFunction()); | |
114 } else { | |
115 assertEquals(content[p], property_mirror.value().value(), | |
116 'property ' + p + ' has unexpected value'); | |
117 } | |
118 count++; | |
119 } | |
120 | |
121 // 'arguments' and might be exposed in the local and closure scope. Just | |
122 // ignore this. | |
123 var scope_size = scope.scopeObject().properties().length; | |
124 if (!scope.scopeObject().property('arguments').isUndefined()) { | |
125 scope_size--; | |
126 } | |
127 // Temporary variables introduced by the parser have not been materialized. | |
128 assertTrue(scope.scopeObject().property('').isUndefined()); | |
129 | |
130 if (count != scope_size) { | |
131 print('Names found in scope:'); | |
132 var names = scope.scopeObject().propertyNames(); | |
133 for (var i = 0; i < names.length; i++) { | |
134 print(names[i]); | |
135 } | |
136 } | |
137 assertEquals(count, scope_size); | |
138 } | |
139 | |
140 | |
141 function assertEqualsUnlessOptimized(expected, value, f) { | |
142 try { | |
143 assertEquals(expected, value); | |
144 } catch (e) { | |
145 assertOptimized(f); | |
146 } | |
147 } | |
148 | |
149 // Simple empty block scope in local scope. | |
150 BeginTest("Local block 1"); | |
151 | |
152 function local_block_1() { | |
153 { | |
154 debugger; | |
155 } | |
156 } | |
157 | |
158 listener_delegate = function(exec_state) { | |
159 CheckScopeChain([debug.ScopeType.Local, | |
160 debug.ScopeType.Script, | |
161 debug.ScopeType.Global], exec_state); | |
162 CheckScopeContent({}, 0, exec_state); | |
163 }; | |
164 local_block_1(); | |
165 EndTest(); | |
166 | |
167 | |
168 // Simple empty block scope in local scope with a parameter. | |
169 BeginTest("Local 2"); | |
170 | |
171 function local_2(a) { | |
172 { | |
173 debugger; | |
174 } | |
175 } | |
176 | |
177 listener_delegate = function(exec_state) { | |
178 CheckScopeChain([debug.ScopeType.Local, | |
179 debug.ScopeType.Script, | |
180 debug.ScopeType.Global], exec_state); | |
181 CheckScopeContent({a:1}, 0, exec_state); | |
182 }; | |
183 local_2(1); | |
184 EndTest(); | |
185 | |
186 | |
187 // Local scope with a parameter and a local variable. | |
188 BeginTest("Local 3"); | |
189 | |
190 function local_3(a) { | |
191 let x = 3; | |
192 debugger; | |
193 } | |
194 | |
195 listener_delegate = function(exec_state) { | |
196 CheckScopeChain([debug.ScopeType.Local, | |
197 debug.ScopeType.Script, | |
198 debug.ScopeType.Global], exec_state); | |
199 CheckScopeContent({a:1,x:3}, 0, exec_state); | |
200 }; | |
201 local_3(1); | |
202 EndTest(); | |
203 | |
204 | |
205 // Local scope with parameters and local variables. | |
206 BeginTest("Local 4"); | |
207 | |
208 function local_4(a, b) { | |
209 let x = 3; | |
210 let y = 4; | |
211 debugger; | |
212 } | |
213 | |
214 listener_delegate = function(exec_state) { | |
215 CheckScopeChain([debug.ScopeType.Local, | |
216 debug.ScopeType.Script, | |
217 debug.ScopeType.Global], exec_state); | |
218 CheckScopeContent({a:1,b:2,x:3,y:4}, 0, exec_state); | |
219 }; | |
220 local_4(1, 2); | |
221 EndTest(); | |
222 | |
223 | |
224 // Single variable in a block scope. | |
225 BeginTest("Local 5"); | |
226 | |
227 function local_5(a) { | |
228 { | |
229 let x = 5; | |
230 debugger; | |
231 } | |
232 } | |
233 | |
234 listener_delegate = function(exec_state) { | |
235 CheckScopeChain([debug.ScopeType.Block, | |
236 debug.ScopeType.Local, | |
237 debug.ScopeType.Script, | |
238 debug.ScopeType.Global], exec_state); | |
239 CheckScopeContent({x:5}, 0, exec_state); | |
240 CheckScopeContent({a:1}, 1, exec_state); | |
241 }; | |
242 local_5(1); | |
243 EndTest(); | |
244 | |
245 | |
246 // Two variables in a block scope. | |
247 BeginTest("Local 6"); | |
248 | |
249 function local_6(a) { | |
250 { | |
251 let x = 6; | |
252 let y = 7; | |
253 debugger; | |
254 } | |
255 } | |
256 | |
257 listener_delegate = function(exec_state) { | |
258 CheckScopeChain([debug.ScopeType.Block, | |
259 debug.ScopeType.Local, | |
260 debug.ScopeType.Script, | |
261 debug.ScopeType.Global], exec_state); | |
262 CheckScopeContent({x:6,y:7}, 0, exec_state); | |
263 CheckScopeContent({a:1}, 1, exec_state); | |
264 }; | |
265 local_6(1); | |
266 EndTest(); | |
267 | |
268 | |
269 // Two variables in a block scope. | |
270 BeginTest("Local 7"); | |
271 | |
272 function local_7(a) { | |
273 { | |
274 { | |
275 let x = 8; | |
276 debugger; | |
277 } | |
278 } | |
279 } | |
280 | |
281 listener_delegate = function(exec_state) { | |
282 CheckScopeChain([debug.ScopeType.Block, | |
283 debug.ScopeType.Local, | |
284 debug.ScopeType.Script, | |
285 debug.ScopeType.Global], exec_state); | |
286 CheckScopeContent({x:8}, 0, exec_state); | |
287 CheckScopeContent({a:1}, 1, exec_state); | |
288 }; | |
289 local_7(1); | |
290 EndTest(); | |
291 | |
292 | |
293 // Simple closure formed by returning an inner function referering to an outer | |
294 // block local variable and an outer function's parameter. | |
295 BeginTest("Closure 1"); | |
296 | |
297 function closure_1(a) { | |
298 var x = 2; | |
299 let y = 3; | |
300 if (true) { | |
301 let z = 4; | |
302 function f() { | |
303 debugger; | |
304 return a + x + y + z; | |
305 }; | |
306 return f; | |
307 } | |
308 } | |
309 | |
310 listener_delegate = function(exec_state) { | |
311 CheckScopeChain([debug.ScopeType.Local, | |
312 debug.ScopeType.Block, | |
313 debug.ScopeType.Closure, | |
314 debug.ScopeType.Script, | |
315 debug.ScopeType.Global], exec_state); | |
316 CheckScopeContent({}, 0, exec_state); | |
317 CheckScopeContent({a:1,x:2,y:3}, 2, exec_state); | |
318 }; | |
319 closure_1(1)(); | |
320 EndTest(); | |
321 | |
322 | |
323 // Simple for-in loop over the keys of an object. | |
324 BeginTest("For loop 1"); | |
325 | |
326 function for_loop_1() { | |
327 for (let x in {y:undefined}) { | |
328 debugger; | |
329 } | |
330 } | |
331 | |
332 listener_delegate = function(exec_state) { | |
333 CheckScopeChain([debug.ScopeType.Block, | |
334 debug.ScopeType.Local, | |
335 debug.ScopeType.Script, | |
336 debug.ScopeType.Global], exec_state); | |
337 CheckScopeContent({x:'y'}, 0, exec_state); | |
338 // The function scope contains a temporary iteration variable, but it is | |
339 // hidden to the debugger. | |
340 }; | |
341 for_loop_1(); | |
342 EndTest(); | |
343 | |
344 | |
345 // For-in loop over the keys of an object with a block scoped let variable | |
346 // shadowing the iteration variable. | |
347 BeginTest("For loop 2"); | |
348 | |
349 function for_loop_2() { | |
350 for (let x in {y:undefined}) { | |
351 let x = 3; | |
352 debugger; | |
353 } | |
354 } | |
355 | |
356 listener_delegate = function(exec_state) { | |
357 CheckScopeChain([debug.ScopeType.Block, | |
358 debug.ScopeType.Block, | |
359 debug.ScopeType.Local, | |
360 debug.ScopeType.Script, | |
361 debug.ScopeType.Global], exec_state); | |
362 CheckScopeContent({x:3}, 0, exec_state); | |
363 CheckScopeContent({x:'y'}, 1, exec_state); | |
364 // The function scope contains a temporary iteration variable, hidden to the | |
365 // debugger. | |
366 }; | |
367 for_loop_2(); | |
368 EndTest(); | |
369 | |
370 | |
371 // Simple for loop. | |
372 BeginTest("For loop 3"); | |
373 | |
374 function for_loop_3() { | |
375 for (let x = 3; x < 4; ++x) { | |
376 debugger; | |
377 } | |
378 } | |
379 | |
380 listener_delegate = function(exec_state) { | |
381 CheckScopeChain([debug.ScopeType.Block, | |
382 debug.ScopeType.Local, | |
383 debug.ScopeType.Script, | |
384 debug.ScopeType.Global], exec_state); | |
385 CheckScopeContent({x:3}, 0, exec_state); | |
386 CheckScopeContent({}, 1, exec_state); | |
387 }; | |
388 for_loop_3(); | |
389 EndTest(); | |
390 | |
391 | |
392 // For loop with a block scoped let variable shadowing the iteration variable. | |
393 BeginTest("For loop 4"); | |
394 | |
395 function for_loop_4() { | |
396 for (let x = 3; x < 4; ++x) { | |
397 let x = 5; | |
398 debugger; | |
399 } | |
400 } | |
401 | |
402 listener_delegate = function(exec_state) { | |
403 CheckScopeChain([debug.ScopeType.Block, | |
404 debug.ScopeType.Block, | |
405 debug.ScopeType.Local, | |
406 debug.ScopeType.Script, | |
407 debug.ScopeType.Global], exec_state); | |
408 CheckScopeContent({x:5}, 0, exec_state); | |
409 CheckScopeContent({x:3}, 1, exec_state); | |
410 CheckScopeContent({}, 2, exec_state); | |
411 }; | |
412 for_loop_4(); | |
413 EndTest(); | |
414 | |
415 | |
416 // For loop with two variable declarations. | |
417 BeginTest("For loop 5"); | |
418 | |
419 function for_loop_5() { | |
420 for (let x = 3, y = 5; x < 4; ++x) { | |
421 debugger; | |
422 } | |
423 } | |
424 | |
425 listener_delegate = function(exec_state) { | |
426 CheckScopeChain([debug.ScopeType.Block, | |
427 debug.ScopeType.Local, | |
428 debug.ScopeType.Script, | |
429 debug.ScopeType.Global], exec_state); | |
430 CheckScopeContent({x:3,y:5}, 0, exec_state); | |
431 CheckScopeContent({}, 1, exec_state); | |
432 }; | |
433 for_loop_5(); | |
434 EndTest(); | |
435 | |
436 | |
437 // Uninitialized variables | |
438 BeginTest("Uninitialized 1"); | |
439 | |
440 function uninitialized_1() { | |
441 { | |
442 debugger; | |
443 let x = 1; | |
444 } | |
445 } | |
446 | |
447 listener_delegate = function(exec_state) { | |
448 CheckScopeChain([debug.ScopeType.Block, | |
449 debug.ScopeType.Local, | |
450 debug.ScopeType.Script, | |
451 debug.ScopeType.Global], exec_state); | |
452 CheckScopeContent({x:undefined}, 0, exec_state); | |
453 }; | |
454 uninitialized_1(); | |
455 EndTest(); | |
456 | |
457 | |
458 // Block scopes shadowing | |
459 BeginTest("Block scopes shadowing 1"); | |
460 function shadowing_1() { | |
461 let i = 0; | |
462 { | |
463 let i = 5; | |
464 debugger; | |
465 } | |
466 assertEquals(0, i); | |
467 } | |
468 | |
469 listener_delegate = function (exec_state) { | |
470 assertEqualsUnlessOptimized(5, exec_state.frame(0).evaluate("i").value()); | |
471 } | |
472 shadowing_1(); | |
473 EndTest(); | |
474 | |
475 | |
476 // Block scopes shadowing | |
477 BeginTest("Block scopes shadowing 2"); | |
478 function shadowing_2() { | |
479 let i = 0; | |
480 { | |
481 let j = 5; | |
482 debugger; | |
483 } | |
484 } | |
485 | |
486 listener_delegate = function (exec_state) { | |
487 assertEqualsUnlessOptimized(0, exec_state.frame(0).evaluate("i").value()); | |
488 assertEqualsUnlessOptimized(5, exec_state.frame(0).evaluate("j").value()); | |
489 } | |
490 shadowing_2(); | |
491 EndTest(); | |
OLD | NEW |