OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
2 | 2 |
3 // Check that we can traverse very deep stacks of ConsStrings using | 3 // Check that we can traverse very deep stacks of ConsStrings using |
4 // StringInputBuffer. Check that Get(int) works on very deep stacks | 4 // StringInputBuffer. Check that Get(int) works on very deep stacks |
5 // of ConsStrings. These operations may not be very fast, but they | 5 // of ConsStrings. These operations may not be very fast, but they |
6 // should be possible without getting errors due to too deep recursion. | 6 // should be possible without getting errors due to too deep recursion. |
7 | 7 |
8 #include <stdlib.h> | 8 #include <stdlib.h> |
9 | 9 |
10 #include "v8.h" | 10 #include "v8.h" |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 printf("4\n"); | 234 printf("4\n"); |
235 Handle<String> left_deep_asymmetric = | 235 Handle<String> left_deep_asymmetric = |
236 ConstructLeft(building_blocks, SUPER_DEEP_DEPTH); | 236 ConstructLeft(building_blocks, SUPER_DEEP_DEPTH); |
237 Handle<String> right_deep_asymmetric = | 237 Handle<String> right_deep_asymmetric = |
238 ConstructRight(building_blocks, SUPER_DEEP_DEPTH); | 238 ConstructRight(building_blocks, SUPER_DEEP_DEPTH); |
239 printf("5\n"); | 239 printf("5\n"); |
240 TraverseFirst(left_asymmetric, left_deep_asymmetric, 1050); | 240 TraverseFirst(left_asymmetric, left_deep_asymmetric, 1050); |
241 printf("6\n"); | 241 printf("6\n"); |
242 TraverseFirst(left_asymmetric, right_deep_asymmetric, 65536); | 242 TraverseFirst(left_asymmetric, right_deep_asymmetric, 65536); |
243 printf("7\n"); | 243 printf("7\n"); |
244 Handle<String> right_deep_slice = | |
245 Factory::NewStringSlice(left_deep_asymmetric, | |
246 left_deep_asymmetric->length() - 1050, | |
247 left_deep_asymmetric->length() - 50); | |
248 Handle<String> left_deep_slice = | |
249 Factory::NewStringSlice(right_deep_asymmetric, | |
250 right_deep_asymmetric->length() - 1050, | |
251 right_deep_asymmetric->length() - 50); | |
252 printf("8\n"); | |
253 Traverse(right_deep_slice, left_deep_slice); | |
254 printf("9\n"); | |
255 FlattenString(left_asymmetric); | 244 FlattenString(left_asymmetric); |
256 printf("10\n"); | 245 printf("10\n"); |
257 Traverse(flat, left_asymmetric); | 246 Traverse(flat, left_asymmetric); |
258 printf("11\n"); | 247 printf("11\n"); |
259 FlattenString(right_asymmetric); | 248 FlattenString(right_asymmetric); |
260 printf("12\n"); | 249 printf("12\n"); |
261 Traverse(flat, right_asymmetric); | 250 Traverse(flat, right_asymmetric); |
262 printf("14\n"); | 251 printf("14\n"); |
263 FlattenString(symmetric); | 252 FlattenString(symmetric); |
264 printf("15\n"); | 253 printf("15\n"); |
265 Traverse(flat, symmetric); | 254 Traverse(flat, symmetric); |
266 printf("16\n"); | 255 printf("16\n"); |
267 FlattenString(left_deep_asymmetric); | 256 FlattenString(left_deep_asymmetric); |
268 printf("18\n"); | 257 printf("18\n"); |
269 } | 258 } |
270 | 259 |
271 | 260 |
272 static Handle<String> SliceOf(Handle<String> underlying) { | |
273 int start = gen() % underlying->length(); | |
274 int end = start + gen() % (underlying->length() - start); | |
275 return Factory::NewStringSlice(underlying, | |
276 start, | |
277 end); | |
278 } | |
279 | |
280 | |
281 static Handle<String> ConstructSliceTree( | |
282 Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS], | |
283 int from, | |
284 int to) { | |
285 CHECK(to > from); | |
286 if (to - from <= 1) | |
287 return SliceOf(building_blocks[from % NUMBER_OF_BUILDING_BLOCKS]); | |
288 if (to - from == 2) { | |
289 Handle<String> lhs = building_blocks[from % NUMBER_OF_BUILDING_BLOCKS]; | |
290 if (gen() % 2 == 0) | |
291 lhs = SliceOf(lhs); | |
292 Handle<String> rhs = building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS]; | |
293 if (gen() % 2 == 0) | |
294 rhs = SliceOf(rhs); | |
295 return Factory::NewConsString(lhs, rhs); | |
296 } | |
297 Handle<String> part1 = | |
298 ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2)); | |
299 Handle<String> part2 = | |
300 ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to); | |
301 Handle<String> branch = Factory::NewConsString(part1, part2); | |
302 if (gen() % 2 == 0) | |
303 return branch; | |
304 return(SliceOf(branch)); | |
305 } | |
306 | |
307 | |
308 TEST(Slice) { | |
309 printf("TestSlice\n"); | |
310 InitializeVM(); | |
311 v8::HandleScope scope; | |
312 Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS]; | |
313 ZoneScope zone(DELETE_ON_EXIT); | |
314 InitializeBuildingBlocks(building_blocks); | |
315 | |
316 seed = 42; | |
317 Handle<String> slice_tree = | |
318 ConstructSliceTree(building_blocks, 0, DEEP_DEPTH); | |
319 seed = 42; | |
320 Handle<String> flat_slice_tree = | |
321 ConstructSliceTree(building_blocks, 0, DEEP_DEPTH); | |
322 FlattenString(flat_slice_tree); | |
323 Traverse(flat_slice_tree, slice_tree); | |
324 } | |
325 | |
326 static const int DEEP_ASCII_DEPTH = 100000; | 261 static const int DEEP_ASCII_DEPTH = 100000; |
327 | 262 |
328 | 263 |
329 TEST(DeepAscii) { | 264 TEST(DeepAscii) { |
330 printf("TestDeepAscii\n"); | 265 printf("TestDeepAscii\n"); |
331 InitializeVM(); | 266 InitializeVM(); |
332 v8::HandleScope scope; | 267 v8::HandleScope scope; |
333 | 268 |
334 char* foo = NewArray<char>(DEEP_ASCII_DEPTH); | 269 char* foo = NewArray<char>(DEEP_ASCII_DEPTH); |
335 for (int i = 0; i < DEEP_ASCII_DEPTH; i++) { | 270 for (int i = 0; i < DEEP_ASCII_DEPTH; i++) { |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
407 } | 342 } |
408 | 343 |
409 const uint16_t* data() const { return data_; } | 344 const uint16_t* data() const { return data_; } |
410 size_t length() const { return length_; } | 345 size_t length() const { return length_; } |
411 | 346 |
412 private: | 347 private: |
413 const uint16_t* data_; | 348 const uint16_t* data_; |
414 size_t length_; | 349 size_t length_; |
415 bool* destructed_; | 350 bool* destructed_; |
416 }; | 351 }; |
417 | |
418 | |
419 // Regression test case for http://crbug.com/9746. The problem was | |
420 // that when we marked objects reachable only through weak pointers, | |
421 // we ended up keeping a sliced symbol alive, even though we already | |
422 // invoked the weak callback on the underlying external string thus | |
423 // deleting its resource. | |
424 TEST(Regress9746) { | |
425 InitializeVM(); | |
426 | |
427 // Setup lengths that guarantee we'll get slices instead of simple | |
428 // flat strings. | |
429 static const int kFullStringLength = String::kMinNonFlatLength * 2; | |
430 static const int kSliceStringLength = String::kMinNonFlatLength + 1; | |
431 | |
432 uint16_t* source = new uint16_t[kFullStringLength]; | |
433 for (int i = 0; i < kFullStringLength; i++) source[i] = '1'; | |
434 char* key = new char[kSliceStringLength]; | |
435 for (int i = 0; i < kSliceStringLength; i++) key[i] = '1'; | |
436 Vector<const char> key_vector(key, kSliceStringLength); | |
437 | |
438 // Allocate an external string resource that keeps track of when it | |
439 // is destructed. | |
440 bool resource_destructed = false; | |
441 TwoByteResource* resource = | |
442 new TwoByteResource(source, kFullStringLength, &resource_destructed); | |
443 | |
444 { | |
445 v8::HandleScope scope; | |
446 | |
447 // Allocate an external string resource and external string. We | |
448 // have to go through the API to get the weak handle and the | |
449 // automatic destruction going. | |
450 Handle<String> string = | |
451 v8::Utils::OpenHandle(*v8::String::NewExternal(resource)); | |
452 | |
453 // Create a slice of the external string. | |
454 Handle<String> slice = | |
455 Factory::NewStringSlice(string, 0, kSliceStringLength); | |
456 CHECK_EQ(kSliceStringLength, slice->length()); | |
457 CHECK(StringShape(*slice).IsSliced()); | |
458 | |
459 // Make sure the slice ends up in old space so we can morph it | |
460 // into a symbol. | |
461 while (Heap::InNewSpace(*slice)) { | |
462 Heap::PerformScavenge(); | |
463 } | |
464 | |
465 // Force the slice into the symbol table. | |
466 slice = Factory::SymbolFromString(slice); | |
467 CHECK(slice->IsSymbol()); | |
468 CHECK(StringShape(*slice).IsSliced()); | |
469 | |
470 Handle<String> buffer(Handle<SlicedString>::cast(slice)->buffer()); | |
471 CHECK(StringShape(*buffer).IsExternal()); | |
472 CHECK(buffer->IsTwoByteRepresentation()); | |
473 | |
474 // Finally, base a script on the slice of the external string and | |
475 // get its wrapper. This allocates yet another weak handle that | |
476 // indirectly refers to the external string. | |
477 Handle<Script> script = Factory::NewScript(slice); | |
478 Handle<JSObject> wrapper = GetScriptWrapper(script); | |
479 } | |
480 | |
481 // When we collect all garbage, we cannot get rid of the sliced | |
482 // symbol entry in the symbol table because it is used by the script | |
483 // kept alive by the weak wrapper. Make sure we don't destruct the | |
484 // external string. | |
485 Heap::CollectAllGarbage(false); | |
486 CHECK(!resource_destructed); | |
487 | |
488 { | |
489 v8::HandleScope scope; | |
490 | |
491 // Make sure the sliced symbol is still in the table. | |
492 Handle<String> symbol = Factory::LookupSymbol(key_vector); | |
493 CHECK(StringShape(*symbol).IsSliced()); | |
494 | |
495 // Make sure the buffer is still a two-byte external string. | |
496 Handle<String> buffer(Handle<SlicedString>::cast(symbol)->buffer()); | |
497 CHECK(StringShape(*buffer).IsExternal()); | |
498 CHECK(buffer->IsTwoByteRepresentation()); | |
499 } | |
500 | |
501 // Forcing another garbage collection should let us get rid of the | |
502 // slice from the symbol table. The external string remains in the | |
503 // heap until the next GC. | |
504 Heap::CollectAllGarbage(false); | |
505 CHECK(!resource_destructed); | |
506 v8::HandleScope scope; | |
507 Handle<String> key_string = Factory::NewStringFromAscii(key_vector); | |
508 String* out; | |
509 CHECK(!Heap::LookupSymbolIfExists(*key_string, &out)); | |
510 | |
511 // Forcing yet another garbage collection must allow us to finally | |
512 // get rid of the external string. | |
513 Heap::CollectAllGarbage(false); | |
514 CHECK(resource_destructed); | |
515 | |
516 delete[] source; | |
517 delete[] key; | |
518 } | |
OLD | NEW |