| 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 |