Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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" |
| 11 | 11 |
| 12 #include "api.h" | 12 #include "api.h" |
| 13 #include "factory.h" | 13 #include "factory.h" |
| 14 #include "objects.h" | 14 #include "objects.h" |
| 15 #include "cctest.h" | 15 #include "cctest.h" |
| 16 #include "zone-inl.h" | 16 #include "zone-inl.h" |
| 17 | 17 |
| 18 unsigned int seed = 123; | 18 // Adapted from http://en.wikipedia.org/wiki/Multiply-with-carry |
| 19 class RandomNumberGenerator { | |
|
Yang
2012/12/10 13:45:29
You could also make a thin wrapper around v8's RNG
drcarney
2012/12/11 10:08:24
Okay. I'll clean it up in another cl. I see that t
| |
| 20 public: | |
| 21 RandomNumberGenerator() { | |
| 22 init(); | |
| 23 } | |
| 19 | 24 |
| 20 static uint32_t gen() { | 25 void init(uint32_t seed = 0x5688c73e) { |
| 21 uint64_t z; | 26 static const uint32_t phi = 0x9e3779b9; |
| 22 z = seed; | 27 c = 362436; |
| 23 z *= 279470273; | 28 i = kQSize-1; |
| 24 z %= 4294967291U; | 29 Q[0] = seed; |
| 25 seed = static_cast<unsigned int>(z); | 30 Q[1] = seed + phi; |
| 26 return static_cast<uint32_t>(seed >> 16); | 31 Q[2] = seed + phi + phi; |
| 27 } | 32 for (unsigned j = 3; j < kQSize; j++) |
|
Yang
2012/12/10 13:45:29
add brackets if the body of for is not on the same
| |
| 33 Q[j] = Q[j - 3] ^ Q[j - 2] ^ phi ^ j; | |
| 34 } | |
| 35 | |
| 36 uint32_t next() { | |
| 37 uint64_t a = 18782; | |
| 38 uint32_t r = 0xfffffffe; | |
| 39 i = (i + 1) & (kQSize-1); | |
| 40 uint64_t t = a * Q[i] + c; | |
| 41 c = (t >> 32); | |
| 42 uint32_t x = t + c; | |
| 43 if (x < c) { | |
| 44 x++; | |
| 45 c++; | |
| 46 } | |
| 47 return (Q[i] = r - x); | |
| 48 } | |
| 49 | |
| 50 uint32_t next(int max) { | |
| 51 return next() % max; | |
| 52 } | |
| 53 | |
| 54 bool next(double threshold) { | |
| 55 ASSERT(threshold >= 0.0 && threshold <= 1.0); | |
| 56 if (threshold == 1.0) | |
| 57 return true; | |
|
Yang
2012/12/10 13:45:29
no line breaks for single-line if.
| |
| 58 if (threshold == 0.0) | |
| 59 return false; | |
| 60 uint32_t value = next() % 100000; | |
| 61 return threshold > static_cast<double>(value)/100000.0; | |
| 62 } | |
| 63 | |
| 64 private: | |
| 65 static const uint32_t kQSize = 4096; | |
| 66 uint32_t Q[kQSize]; | |
| 67 uint32_t c; | |
| 68 uint32_t i; | |
| 69 }; | |
| 28 | 70 |
| 29 | 71 |
| 30 using namespace v8::internal; | 72 using namespace v8::internal; |
| 31 | 73 |
| 32 static v8::Persistent<v8::Context> env; | 74 static v8::Persistent<v8::Context> env; |
| 33 | 75 |
| 34 | 76 |
| 35 static void InitializeVM() { | 77 static void InitializeVM() { |
| 36 if (env.IsEmpty()) { | 78 if (env.IsEmpty()) { |
| 37 v8::HandleScope scope; | 79 v8::HandleScope scope; |
| 38 const char* extensions[] = { "v8/print" }; | 80 const char* extensions[] = { "v8/print" }; |
| 39 v8::ExtensionConfiguration config(1, extensions); | 81 v8::ExtensionConfiguration config(1, extensions); |
| 40 env = v8::Context::New(&config); | 82 env = v8::Context::New(&config); |
| 41 } | 83 } |
| 42 v8::HandleScope scope; | 84 v8::HandleScope scope; |
| 43 env->Enter(); | 85 env->Enter(); |
| 44 } | 86 } |
| 45 | 87 |
| 46 | 88 |
| 47 static const int NUMBER_OF_BUILDING_BLOCKS = 128; | 89 static const int NUMBER_OF_BUILDING_BLOCKS = 256; |
| 48 static const int DEEP_DEPTH = 8 * 1024; | 90 static const int DEEP_DEPTH = 8 * 1024; |
| 49 static const int SUPER_DEEP_DEPTH = 80 * 1024; | 91 static const int SUPER_DEEP_DEPTH = 80 * 1024; |
| 50 | 92 |
| 51 | 93 |
| 52 class Resource: public v8::String::ExternalStringResource, | 94 class Resource: public v8::String::ExternalStringResource, |
| 53 public ZoneObject { | 95 public ZoneObject { |
| 54 public: | 96 public: |
| 55 explicit Resource(Vector<const uc16> string): data_(string.start()) { | 97 explicit Resource(Vector<const uc16> string): data_(string.start()) { |
| 56 length_ = string.length(); | 98 length_ = string.length(); |
| 57 } | 99 } |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 72 } | 114 } |
| 73 virtual const char* data() const { return data_; } | 115 virtual const char* data() const { return data_; } |
| 74 virtual size_t length() const { return length_; } | 116 virtual size_t length() const { return length_; } |
| 75 | 117 |
| 76 private: | 118 private: |
| 77 const char* data_; | 119 const char* data_; |
| 78 size_t length_; | 120 size_t length_; |
| 79 }; | 121 }; |
| 80 | 122 |
| 81 | 123 |
| 82 static void InitializeBuildingBlocks( | 124 static void InitializeBuildingBlocks(Handle<String>* building_blocks, |
| 83 Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS]) { | 125 int bb_length, |
| 126 bool long_blocks, | |
| 127 RandomNumberGenerator* rng) { | |
| 84 // A list of pointers that we don't have any interest in cleaning up. | 128 // A list of pointers that we don't have any interest in cleaning up. |
| 85 // If they are reachable from a root then leak detection won't complain. | 129 // If they are reachable from a root then leak detection won't complain. |
| 86 Zone* zone = Isolate::Current()->runtime_zone(); | 130 Zone* zone = Isolate::Current()->runtime_zone(); |
| 87 for (int i = 0; i < NUMBER_OF_BUILDING_BLOCKS; i++) { | 131 for (int i = 0; i < bb_length; i++) { |
| 88 int len = gen() % 16; | 132 int len = rng->next(16); |
| 89 if (len > 14) { | 133 int slice_head_chars = 0; |
| 134 int slice_tail_chars = 0; | |
| 135 int slice_depth = 0; | |
| 136 for (int i = 0; i < 3; i++) { | |
| 137 if (rng->next(0.35)) slice_depth++; | |
| 138 } | |
| 139 while (slice_head_chars == 0 && slice_tail_chars == 0) { | |
| 140 slice_head_chars = rng->next(15); | |
|
Yang
2012/12/10 13:45:29
you could avoid the while loop if you just add 1 t
drcarney
2012/12/11 10:08:24
I want to allow at most one of the slices to be ze
| |
| 141 slice_tail_chars = rng->next(12); | |
| 142 } | |
| 143 if (long_blocks) { | |
| 144 // Generate building blocks which will never be merged | |
| 145 len += ConsString::kMinLength + 1; | |
| 146 } else if (len > 14) { | |
| 90 len += 1234; | 147 len += 1234; |
| 91 } | 148 } |
| 92 switch (gen() % 4) { | 149 // Don't slice 0 length strings. |
| 150 if (len == 0) slice_depth = 0; | |
| 151 int slice_length = slice_depth*(slice_head_chars + slice_tail_chars); | |
| 152 len += slice_length; | |
| 153 switch (rng->next(5)) { | |
| 93 case 0: { | 154 case 0: { |
| 94 uc16 buf[2000]; | 155 uc16 buf[2000]; |
| 95 for (int j = 0; j < len; j++) { | 156 for (int j = 0; j < len; j++) { |
| 96 buf[j] = gen() % 65536; | 157 buf[j] = rng->next(65536); |
|
Yang
2012/12/10 13:45:29
I'd prefer (1 << 16) or 0x10000, but this is not w
| |
| 97 } | 158 } |
| 98 building_blocks[i] = | 159 building_blocks[i] = |
| 99 FACTORY->NewStringFromTwoByte(Vector<const uc16>(buf, len)); | 160 FACTORY->NewStringFromTwoByte(Vector<const uc16>(buf, len)); |
| 100 for (int j = 0; j < len; j++) { | 161 for (int j = 0; j < len; j++) { |
| 101 CHECK_EQ(buf[j], building_blocks[i]->Get(j)); | 162 CHECK_EQ(buf[j], building_blocks[i]->Get(j)); |
| 102 } | 163 } |
| 103 break; | 164 break; |
| 104 } | 165 } |
| 105 case 1: { | 166 case 1: { |
| 106 char buf[2000]; | 167 char buf[2000]; |
| 107 for (int j = 0; j < len; j++) { | 168 for (int j = 0; j < len; j++) { |
| 108 buf[j] = gen() % 128; | 169 buf[j] = rng->next(128); |
| 109 } | 170 } |
| 110 building_blocks[i] = | 171 building_blocks[i] = |
| 111 FACTORY->NewStringFromAscii(Vector<const char>(buf, len)); | 172 FACTORY->NewStringFromAscii(Vector<const char>(buf, len)); |
| 112 for (int j = 0; j < len; j++) { | 173 for (int j = 0; j < len; j++) { |
| 113 CHECK_EQ(buf[j], building_blocks[i]->Get(j)); | 174 CHECK_EQ(buf[j], building_blocks[i]->Get(j)); |
| 114 } | 175 } |
| 115 break; | 176 break; |
| 116 } | 177 } |
| 117 case 2: { | 178 case 2: { |
| 118 uc16* buf = zone->NewArray<uc16>(len); | 179 uc16* buf = zone->NewArray<uc16>(len); |
| 119 for (int j = 0; j < len; j++) { | 180 for (int j = 0; j < len; j++) { |
| 120 buf[j] = gen() % 65536; | 181 buf[j] = rng->next(65536); |
| 121 } | 182 } |
| 122 Resource* resource = new(zone) Resource(Vector<const uc16>(buf, len)); | 183 Resource* resource = new(zone) Resource(Vector<const uc16>(buf, len)); |
| 123 building_blocks[i] = FACTORY->NewExternalStringFromTwoByte(resource); | 184 building_blocks[i] = FACTORY->NewExternalStringFromTwoByte(resource); |
| 124 for (int j = 0; j < len; j++) { | 185 for (int j = 0; j < len; j++) { |
| 125 CHECK_EQ(buf[j], building_blocks[i]->Get(j)); | 186 CHECK_EQ(buf[j], building_blocks[i]->Get(j)); |
| 126 } | 187 } |
| 127 break; | 188 break; |
| 128 } | 189 } |
| 129 case 3: { | 190 case 3: { |
|
Yang
2012/12/10 13:45:29
I don't see what the difference between case 1 and
| |
| 130 char* buf = NewArray<char>(len); | 191 char* buf = NewArray<char>(len); |
| 131 for (int j = 0; j < len; j++) { | 192 for (int j = 0; j < len; j++) { |
| 132 buf[j] = gen() % 128; | 193 buf[j] = rng->next(128); |
| 133 } | 194 } |
| 134 building_blocks[i] = | 195 building_blocks[i] = |
| 135 FACTORY->NewStringFromAscii(Vector<const char>(buf, len)); | 196 FACTORY->NewStringFromAscii(Vector<const char>(buf, len)); |
| 136 for (int j = 0; j < len; j++) { | 197 for (int j = 0; j < len; j++) { |
| 137 CHECK_EQ(buf[j], building_blocks[i]->Get(j)); | 198 CHECK_EQ(buf[j], building_blocks[i]->Get(j)); |
| 138 } | 199 } |
| 139 DeleteArray<char>(buf); | 200 DeleteArray<char>(buf); |
| 140 break; | 201 break; |
| 141 } | 202 } |
| 203 case 4: { | |
| 204 char* buf = zone->NewArray<char>(len); | |
| 205 for (int j = 0; j < len; j++) { | |
| 206 buf[j] = rng->next(128); | |
| 207 } | |
| 208 AsciiResource* resource = | |
| 209 new(zone) AsciiResource(Vector<const char>(buf, len)); | |
| 210 building_blocks[i] = FACTORY->NewExternalStringFromAscii(resource); | |
| 211 for (int j = 0; j < len; j++) { | |
| 212 CHECK_EQ(buf[j], building_blocks[i]->Get(j)); | |
| 213 } | |
| 214 break; | |
| 215 } | |
| 142 } | 216 } |
| 217 for (int j = slice_depth; j > 0; j--) { | |
| 218 building_blocks[i] = FACTORY->NewSubString( | |
| 219 building_blocks[i], | |
| 220 slice_head_chars, | |
| 221 building_blocks[i]->length() - slice_tail_chars); | |
| 222 } | |
| 223 CHECK(len == building_blocks[i]->length() + slice_length); | |
| 143 } | 224 } |
| 144 } | 225 } |
| 145 | 226 |
| 146 | 227 |
| 147 static Handle<String> ConstructLeft( | 228 static Handle<String> ConstructLeft( |
| 148 Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS], | 229 Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS], |
| 149 int depth) { | 230 int depth) { |
| 150 Handle<String> answer = FACTORY->NewStringFromAscii(CStrVector("")); | 231 Handle<String> answer = FACTORY->NewStringFromAscii(CStrVector("")); |
| 151 for (int i = 0; i < depth; i++) { | 232 for (int i = 0; i < depth; i++) { |
| 152 answer = FACTORY->NewConsString( | 233 answer = FACTORY->NewConsString( |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 191 } | 272 } |
| 192 | 273 |
| 193 | 274 |
| 194 static Handle<String> ConstructBalanced( | 275 static Handle<String> ConstructBalanced( |
| 195 Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS]) { | 276 Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS]) { |
| 196 return ConstructBalancedHelper(building_blocks, 0, DEEP_DEPTH); | 277 return ConstructBalancedHelper(building_blocks, 0, DEEP_DEPTH); |
| 197 } | 278 } |
| 198 | 279 |
| 199 | 280 |
| 200 static StringInputBuffer buffer; | 281 static StringInputBuffer buffer; |
| 201 | 282 static ConsStringIteratorOp cons_string_iterator_op_1; |
| 283 static ConsStringIteratorOp cons_string_iterator_op_2; | |
| 202 | 284 |
| 203 static void Traverse(Handle<String> s1, Handle<String> s2) { | 285 static void Traverse(Handle<String> s1, Handle<String> s2) { |
| 204 int i = 0; | 286 int i = 0; |
| 205 buffer.Reset(*s1); | 287 buffer.Reset(*s1); |
| 288 StringCharacterStream character_stream_1(*s1, 0, &cons_string_iterator_op_1); | |
| 289 StringCharacterStream character_stream_2(*s2, 0, &cons_string_iterator_op_2); | |
| 206 StringInputBuffer buffer2(*s2); | 290 StringInputBuffer buffer2(*s2); |
| 207 while (buffer.has_more()) { | 291 while (buffer.has_more()) { |
| 208 CHECK(buffer2.has_more()); | 292 CHECK(buffer2.has_more()); |
| 293 CHECK(character_stream_1.HasMore()); | |
| 294 CHECK(character_stream_2.HasMore()); | |
| 209 uint16_t c = buffer.GetNext(); | 295 uint16_t c = buffer.GetNext(); |
| 210 CHECK_EQ(c, buffer2.GetNext()); | 296 CHECK_EQ(c, buffer2.GetNext()); |
| 297 CHECK_EQ(c, character_stream_1.GetNext()); | |
| 298 CHECK_EQ(c, character_stream_2.GetNext()); | |
| 211 i++; | 299 i++; |
| 212 } | 300 } |
| 301 CHECK(!character_stream_1.HasMore()); | |
| 302 CHECK(!character_stream_2.HasMore()); | |
| 213 CHECK_EQ(s1->length(), i); | 303 CHECK_EQ(s1->length(), i); |
| 214 CHECK_EQ(s2->length(), i); | 304 CHECK_EQ(s2->length(), i); |
| 215 } | 305 } |
| 216 | 306 |
| 217 | 307 |
| 218 static void TraverseFirst(Handle<String> s1, Handle<String> s2, int chars) { | 308 static void TraverseFirst(Handle<String> s1, Handle<String> s2, int chars) { |
| 219 int i = 0; | 309 int i = 0; |
| 220 buffer.Reset(*s1); | 310 buffer.Reset(*s1); |
| 221 StringInputBuffer buffer2(*s2); | 311 StringInputBuffer buffer2(*s2); |
| 312 StringCharacterStream character_stream_1(*s1, 0, &cons_string_iterator_op_1); | |
| 313 StringCharacterStream character_stream_2(*s2, 0, &cons_string_iterator_op_2); | |
| 222 while (buffer.has_more() && i < chars) { | 314 while (buffer.has_more() && i < chars) { |
| 223 CHECK(buffer2.has_more()); | 315 CHECK(buffer2.has_more()); |
| 316 CHECK(character_stream_1.HasMore()); | |
| 317 CHECK(character_stream_2.HasMore()); | |
| 224 uint16_t c = buffer.GetNext(); | 318 uint16_t c = buffer.GetNext(); |
| 225 CHECK_EQ(c, buffer2.GetNext()); | 319 CHECK_EQ(c, buffer2.GetNext()); |
| 320 CHECK_EQ(c, character_stream_1.GetNext()); | |
| 321 CHECK_EQ(c, character_stream_2.GetNext()); | |
| 226 i++; | 322 i++; |
| 227 } | 323 } |
| 228 s1->Get(s1->length() - 1); | 324 s1->Get(s1->length() - 1); |
| 229 s2->Get(s2->length() - 1); | 325 s2->Get(s2->length() - 1); |
| 230 } | 326 } |
| 231 | 327 |
| 232 | 328 |
| 233 TEST(Traverse) { | 329 TEST(Traverse) { |
| 234 printf("TestTraverse\n"); | 330 printf("TestTraverse\n"); |
| 235 InitializeVM(); | 331 InitializeVM(); |
| 236 v8::HandleScope scope; | 332 v8::HandleScope scope; |
| 237 Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS]; | 333 Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS]; |
| 238 ZoneScope zone(Isolate::Current()->runtime_zone(), DELETE_ON_EXIT); | 334 ZoneScope zone(Isolate::Current()->runtime_zone(), DELETE_ON_EXIT); |
| 239 InitializeBuildingBlocks(building_blocks); | 335 RandomNumberGenerator rng; |
| 336 rng.init(); | |
| 337 InitializeBuildingBlocks( | |
| 338 building_blocks, NUMBER_OF_BUILDING_BLOCKS, false, &rng); | |
| 240 Handle<String> flat = ConstructBalanced(building_blocks); | 339 Handle<String> flat = ConstructBalanced(building_blocks); |
| 241 FlattenString(flat); | 340 FlattenString(flat); |
| 242 Handle<String> left_asymmetric = ConstructLeft(building_blocks, DEEP_DEPTH); | 341 Handle<String> left_asymmetric = ConstructLeft(building_blocks, DEEP_DEPTH); |
| 243 Handle<String> right_asymmetric = ConstructRight(building_blocks, DEEP_DEPTH); | 342 Handle<String> right_asymmetric = ConstructRight(building_blocks, DEEP_DEPTH); |
| 244 Handle<String> symmetric = ConstructBalanced(building_blocks); | 343 Handle<String> symmetric = ConstructBalanced(building_blocks); |
| 245 printf("1\n"); | 344 printf("1\n"); |
| 246 Traverse(flat, symmetric); | 345 Traverse(flat, symmetric); |
| 247 printf("2\n"); | 346 printf("2\n"); |
| 248 Traverse(flat, left_asymmetric); | 347 Traverse(flat, left_asymmetric); |
| 249 printf("3\n"); | 348 printf("3\n"); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 268 printf("14\n"); | 367 printf("14\n"); |
| 269 FlattenString(symmetric); | 368 FlattenString(symmetric); |
| 270 printf("15\n"); | 369 printf("15\n"); |
| 271 Traverse(flat, symmetric); | 370 Traverse(flat, symmetric); |
| 272 printf("16\n"); | 371 printf("16\n"); |
| 273 FlattenString(left_deep_asymmetric); | 372 FlattenString(left_deep_asymmetric); |
| 274 printf("18\n"); | 373 printf("18\n"); |
| 275 } | 374 } |
| 276 | 375 |
| 277 | 376 |
| 377 class ConsStringStats { | |
| 378 public: | |
| 379 ConsStringStats() { | |
| 380 Reset(); | |
| 381 } | |
| 382 void Reset(); | |
| 383 unsigned leaves_; | |
| 384 unsigned empty_leaves_; | |
| 385 unsigned chars_; | |
| 386 unsigned left_traversals_; | |
| 387 unsigned right_traversals_; | |
| 388 private: | |
| 389 DISALLOW_COPY_AND_ASSIGN(ConsStringStats); | |
| 390 }; | |
| 391 | |
| 392 | |
| 393 void ConsStringStats::Reset() { | |
| 394 leaves_ = 0; | |
| 395 empty_leaves_ = 0; | |
| 396 chars_ = 0; | |
| 397 left_traversals_ = 0; | |
| 398 right_traversals_ = 0; | |
| 399 } | |
| 400 | |
| 401 | |
| 402 static void VerifyEqual(const ConsStringStats& a, const ConsStringStats& b) { | |
|
Yang
2012/12/10 13:45:29
This could be made a method of ConsStringStats.
| |
| 403 CHECK(a.leaves_ == b.leaves_); | |
| 404 CHECK(a.empty_leaves_ == b.empty_leaves_); | |
| 405 CHECK(a.chars_ == b.chars_); | |
| 406 CHECK(a.left_traversals_ == b.left_traversals_); | |
| 407 CHECK(a.right_traversals_ == b.right_traversals_); | |
| 408 } | |
| 409 | |
| 410 | |
| 411 class ConsStringGenerationData { | |
| 412 public: | |
| 413 ConsStringGenerationData(); | |
| 414 void Reset(); | |
| 415 // Input variables. | |
| 416 double early_termination_threshold_; | |
| 417 double leftness_; | |
| 418 double rightness_; | |
| 419 double empty_leaf_threshold_; | |
| 420 unsigned max_leaves_; | |
| 421 // Cached data. | |
| 422 Handle<String> building_blocks_[NUMBER_OF_BUILDING_BLOCKS]; | |
| 423 String* empty_string_; | |
| 424 RandomNumberGenerator rng_; | |
| 425 // Stats. | |
| 426 ConsStringStats stats_; | |
| 427 unsigned early_terminations_; | |
| 428 private: | |
| 429 DISALLOW_COPY_AND_ASSIGN(ConsStringGenerationData); | |
| 430 }; | |
| 431 | |
| 432 | |
| 433 ConsStringGenerationData::ConsStringGenerationData() { | |
| 434 rng_.init(); | |
| 435 InitializeBuildingBlocks( | |
| 436 building_blocks_, NUMBER_OF_BUILDING_BLOCKS, true, &rng_); | |
| 437 empty_string_ = Isolate::Current()->heap()->empty_string(); | |
| 438 Reset(); | |
| 439 } | |
| 440 | |
| 441 | |
| 442 void ConsStringGenerationData::Reset() { | |
| 443 early_termination_threshold_ = 0.01; | |
| 444 leftness_ = 0.75; | |
| 445 rightness_ = 0.75; | |
| 446 empty_leaf_threshold_ = 0.02; | |
| 447 max_leaves_ = 1000; | |
| 448 stats_.Reset(); | |
| 449 early_terminations_ = 0; | |
| 450 } | |
| 451 | |
| 452 | |
| 453 void VerifyConsString(ConsString* cons_string, ConsStringStats* stats) { | |
| 454 int left_length = cons_string->first()->length(); | |
| 455 int right_length = cons_string->second()->length(); | |
| 456 CHECK(cons_string->length() == left_length + right_length); | |
| 457 // Check left side. | |
| 458 if (StringShape(cons_string->first()).IsCons()) { | |
|
Yang
2012/12/10 13:45:29
I guess !cons_string->first()->IsConsString() work
| |
| 459 stats->left_traversals_++; | |
| 460 VerifyConsString(ConsString::cast(cons_string->first()), stats); | |
| 461 } else { | |
| 462 CHECK_NE(left_length, 0); | |
| 463 stats->leaves_++; | |
| 464 stats->chars_ += left_length; | |
| 465 } | |
| 466 // Check right side. | |
| 467 if (StringShape(cons_string->second()).IsCons()) { | |
| 468 stats->right_traversals_++; | |
| 469 VerifyConsString(ConsString::cast(cons_string->second()), stats); | |
| 470 } else { | |
| 471 if (right_length == 0) | |
| 472 stats->empty_leaves_++; | |
| 473 stats->leaves_++; | |
| 474 stats->chars_ += right_length; | |
| 475 } | |
| 476 } | |
| 477 | |
| 478 | |
| 479 void VerifyConsStringWithOperator( | |
| 480 ConsString* cons_string, ConsStringStats* stats) { | |
| 481 // Init op. | |
| 482 ConsStringIteratorOp op; | |
| 483 op.Reset(); | |
| 484 // Use response for initial search and on blown stack. | |
| 485 ConsStringIteratorOp::ContinueResponse response; | |
| 486 response.string_ = cons_string; | |
| 487 response.offset_ = 0; | |
| 488 response.type_ = cons_string->map()->instance_type(); | |
| 489 response.length_ = (uint32_t) cons_string->length(); | |
| 490 while (true) { | |
| 491 String* string = op.Operate( | |
| 492 ConsString::cast(response.string_), | |
| 493 &response.offset_, | |
| 494 &response.type_, | |
| 495 &response.length_); | |
|
Yang
2012/12/10 13:45:29
Please format this so that the first argument is i
| |
| 496 CHECK(string != NULL); | |
| 497 while (true) { | |
| 498 // Accumulate stats. | |
| 499 stats->leaves_++; | |
| 500 stats->chars_ += string->length(); | |
| 501 // Check for completion. | |
| 502 bool keep_going_fast_check = op.HasMore(); | |
| 503 bool keep_going = op.ContinueOperation(&response); | |
| 504 if (!keep_going) | |
| 505 return; | |
|
Yang
2012/12/10 13:45:29
no line break here.
| |
| 506 // Verify no false positives for fast check. | |
| 507 CHECK(keep_going_fast_check); | |
| 508 CHECK(response.string_ != NULL); | |
| 509 // Blew stack. Restart outer loop. | |
| 510 if (StringShape(response.string_).IsCons()) | |
| 511 break; | |
|
Yang
2012/12/10 13:45:29
no line break here.
| |
| 512 string = response.string_; | |
| 513 } | |
| 514 }; | |
| 515 } | |
| 516 | |
| 517 | |
| 518 void VerifyConsString(Handle<String> root, ConsStringGenerationData* data) { | |
| 519 // Verify basic data. | |
| 520 CHECK(StringShape(*root).IsCons()); | |
| 521 CHECK((unsigned)root->length() == data->stats_.chars_); | |
| 522 // Recursive verify. | |
| 523 ConsStringStats stats; | |
| 524 VerifyConsString(ConsString::cast(*root), &stats); | |
| 525 VerifyEqual(stats, data->stats_); | |
| 526 // Iteratively verify. | |
| 527 stats.Reset(); | |
| 528 VerifyConsStringWithOperator(ConsString::cast(*root), &stats); | |
| 529 // Don't see these. Must copy over. | |
| 530 stats.empty_leaves_ = data->stats_.empty_leaves_; | |
| 531 stats.left_traversals_ = data->stats_.left_traversals_; | |
| 532 stats.right_traversals_ = data->stats_.right_traversals_; | |
| 533 // Adjust total leaves to compensate. | |
| 534 stats.leaves_ += stats.empty_leaves_; | |
| 535 VerifyEqual(stats, data->stats_); | |
| 536 } | |
| 537 | |
| 538 | |
| 539 static Handle<String> ConstructRandomString( | |
| 540 ConsStringGenerationData* data, | |
|
Yang
2012/12/10 13:45:29
you could move the first argument to the first lin
| |
| 541 unsigned max_recursion) { | |
| 542 // Compute termination characteristics. | |
| 543 bool terminate = false; | |
| 544 bool flat = data->rng_.next(data->empty_leaf_threshold_); | |
| 545 bool terminate_early = data->rng_.next(data->early_termination_threshold_); | |
| 546 if (terminate_early) data->early_terminations_++; | |
| 547 // The obvious condition. | |
| 548 terminate |= max_recursion == 0; | |
| 549 // Flat cons string terminate by definition. | |
| 550 terminate |= flat; | |
| 551 // Cap for max leaves. | |
| 552 terminate |= data->stats_.leaves_ >= data->max_leaves_; | |
| 553 // Roll the dice. | |
| 554 terminate |= terminate_early; | |
| 555 // Compute termination characteristics for each side. | |
| 556 bool terminate_left = terminate || !data->rng_.next(data->leftness_); | |
| 557 bool terminate_right = terminate || !data->rng_.next(data->rightness_); | |
| 558 // Generate left string. | |
| 559 Handle<String> left; | |
| 560 if (terminate_left) { | |
| 561 left = data->building_blocks_[data->rng_.next(NUMBER_OF_BUILDING_BLOCKS)]; | |
| 562 data->stats_.leaves_++; | |
| 563 data->stats_.chars_ += left->length(); | |
| 564 } else { | |
| 565 left = ConstructRandomString(data, max_recursion - 1); | |
| 566 data->stats_.left_traversals_++; | |
| 567 } | |
| 568 // Generate right string. | |
| 569 Handle<String> right; | |
| 570 if (terminate_right) { | |
| 571 right = data->building_blocks_[data->rng_.next(NUMBER_OF_BUILDING_BLOCKS)]; | |
| 572 data->stats_.leaves_++; | |
| 573 data->stats_.chars_ += right->length(); | |
| 574 } else { | |
| 575 right = ConstructRandomString(data, max_recursion - 1); | |
| 576 data->stats_.right_traversals_++; | |
| 577 } | |
| 578 // Build the cons string. | |
| 579 Handle<String> root = FACTORY->NewConsString(left, right); | |
| 580 CHECK(StringShape(*root).IsCons() && !root->IsFlat()); | |
| 581 // Special work needed for flat string. | |
| 582 if (flat) { | |
| 583 data->stats_.empty_leaves_++; | |
| 584 FlattenString(root); | |
| 585 CHECK(StringShape(*root).IsCons() && root->IsFlat()); | |
| 586 } | |
| 587 return root; | |
| 588 } | |
| 589 | |
| 590 | |
| 591 static const int kCharacterStreamRandomCases = 150; | |
| 592 static const int kCharacterStreamEdgeCases = | |
| 593 kCharacterStreamRandomCases + 5; | |
| 594 | |
| 595 | |
| 596 static Handle<String> BuildConsStrings( | |
| 597 int testCase, | |
|
Yang
2012/12/10 13:45:29
first argument on first line, second aligned to fi
| |
| 598 ConsStringGenerationData* data) { | |
| 599 // For random constructions, need to reset the generator. | |
| 600 data->rng_.init(); | |
| 601 for (int j = 0; j < testCase * 50; j++) | |
| 602 data->rng_.next(); | |
|
Yang
2012/12/10 13:45:29
same line or brackets.
| |
| 603 Handle<String> string; | |
| 604 switch (testCase) { | |
| 605 case 0: | |
| 606 return ConstructBalanced(data->building_blocks_); | |
| 607 case 1: | |
| 608 return ConstructLeft(data->building_blocks_, DEEP_DEPTH); | |
| 609 case 2: | |
| 610 return ConstructRight(data->building_blocks_, DEEP_DEPTH); | |
| 611 case 3: | |
| 612 return ConstructLeft(data->building_blocks_, 10); | |
| 613 case 4: | |
| 614 return ConstructRight(data->building_blocks_, 10); | |
| 615 case 5: | |
| 616 return FACTORY->NewConsString( | |
| 617 data->building_blocks_[0], data->building_blocks_[1]); | |
| 618 default: | |
|
Yang
2012/12/10 13:45:29
indentation.
| |
| 619 if (testCase >= kCharacterStreamEdgeCases) { | |
| 620 CHECK(false); | |
| 621 return string; | |
| 622 } | |
| 623 // Random test case. | |
| 624 data->Reset(); | |
| 625 string = ConstructRandomString(data, 200); | |
| 626 AssertNoAllocation no_alloc; | |
| 627 VerifyConsString(string, data); | |
| 628 #ifndef NDEBUG | |
|
Yang
2012/12/10 13:45:29
maybe you mean #ifdef DEBUG?
| |
| 629 printf( | |
| 630 "%s: [%d], %s: [%d], %s: [%d], %s: [%d], %s: [%d], %s: [%d]\n", | |
| 631 "leaves", data->stats_.leaves_, | |
| 632 "empty", data->stats_.empty_leaves_, | |
| 633 "chars", data->stats_.chars_, | |
| 634 "lefts", data->stats_.left_traversals_, | |
| 635 "rights", data->stats_.right_traversals_, | |
| 636 "early_terminations", data->early_terminations_); | |
| 637 #endif | |
| 638 return string; | |
| 639 } | |
| 640 } | |
| 641 | |
| 642 | |
| 643 static void VerifyCharacterStream( | |
| 644 String* flat_string, String* cons_string) { | |
| 645 // Do not want to test ConString traversal on flat string. | |
| 646 CHECK(flat_string->IsFlat()); | |
| 647 CHECK(!StringShape(flat_string).IsCons()); | |
| 648 CHECK(StringShape(cons_string).IsCons()); | |
| 649 // TODO(dcarney) Test stream reset as well. | |
| 650 int length = flat_string->length(); | |
| 651 int outer_iterations = length >= 103 ? 103 : 30; | |
|
Yang
2012/12/10 13:45:29
Why do we need to repeat this test so many times?
| |
| 652 for (int j = 0; j <= outer_iterations; j++) { | |
| 653 int offset = (double)length*(double)j/(double)outer_iterations; // NOLINT | |
|
Yang
2012/12/10 13:45:29
We always use static_cast, reinterpret_cast, etc.
| |
| 654 if (offset < 0) offset = 0; | |
| 655 // Want to test the offset == length case. | |
| 656 if (offset > length) offset = length; | |
| 657 StringCharacterStream flat_stream( | |
| 658 flat_string, (unsigned) offset, &cons_string_iterator_op_1); | |
| 659 StringCharacterStream cons_stream( | |
| 660 cons_string, (unsigned) offset, &cons_string_iterator_op_2); | |
| 661 for (int i = offset; i < length; i++) { | |
| 662 uint16_t c = flat_string->Get(i); | |
| 663 CHECK(flat_stream.HasMore()); | |
| 664 CHECK(cons_stream.HasMore()); | |
| 665 CHECK_EQ(c, flat_stream.GetNext()); | |
| 666 CHECK_EQ(c, cons_stream.GetNext()); | |
| 667 } | |
| 668 CHECK(!flat_stream.HasMore()); | |
| 669 CHECK(!cons_stream.HasMore()); | |
| 670 } | |
| 671 } | |
| 672 | |
| 673 | |
| 674 TEST(StringCharacterStreamEdgeCases) { | |
| 675 printf("TestStringCharacterStreamEdgeCases\n"); | |
| 676 InitializeVM(); | |
| 677 Isolate* isolate = Isolate::Current(); | |
| 678 HandleScope outer_scope(isolate); | |
| 679 ZoneScope zone(Isolate::Current()->runtime_zone(), DELETE_ON_EXIT); | |
| 680 ConsStringGenerationData data; | |
| 681 for (int i = 0; i < kCharacterStreamEdgeCases; i++) { | |
| 682 printf("%d\n", i); | |
| 683 isolate->heap()->CollectAllGarbage( | |
| 684 Heap::kNoGCFlags, "must not allocate in loop"); | |
| 685 AlwaysAllocateScope always_allocate; | |
| 686 HandleScope inner_scope(isolate); | |
| 687 Handle<String> cons_string = BuildConsStrings(i, &data); | |
| 688 Handle<String> flat_string = BuildConsStrings(i, &data); | |
| 689 FlattenString(flat_string); | |
| 690 AssertNoAllocation no_alloc; | |
| 691 CHECK(StringShape(*flat_string).IsCons() && flat_string->IsFlat()); | |
| 692 VerifyCharacterStream(ConsString::cast(*flat_string)->first(), | |
| 693 *cons_string); | |
| 694 } | |
| 695 } | |
| 696 | |
| 697 | |
| 278 static const int DEEP_ASCII_DEPTH = 100000; | 698 static const int DEEP_ASCII_DEPTH = 100000; |
| 279 | 699 |
| 280 | 700 |
| 281 TEST(DeepAscii) { | 701 TEST(DeepAscii) { |
| 282 printf("TestDeepAscii\n"); | 702 printf("TestDeepAscii\n"); |
| 283 InitializeVM(); | 703 InitializeVM(); |
| 284 v8::HandleScope scope; | 704 v8::HandleScope scope; |
| 285 | 705 |
| 286 char* foo = NewArray<char>(DEEP_ASCII_DEPTH); | 706 char* foo = NewArray<char>(DEEP_ASCII_DEPTH); |
| 287 for (int i = 0; i < DEEP_ASCII_DEPTH; i++) { | 707 for (int i = 0; i < DEEP_ASCII_DEPTH; i++) { |
| (...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 708 | 1128 |
| 709 v8::Local<v8::String> expected = v8_str("ascii\x80only\x80string\x80"); | 1129 v8::Local<v8::String> expected = v8_str("ascii\x80only\x80string\x80"); |
| 710 CHECK(expected->Equals(result)); | 1130 CHECK(expected->Equals(result)); |
| 711 } | 1131 } |
| 712 | 1132 |
| 713 | 1133 |
| 714 TEST(IsAscii) { | 1134 TEST(IsAscii) { |
| 715 CHECK(String::IsAscii(static_cast<char*>(NULL), 0)); | 1135 CHECK(String::IsAscii(static_cast<char*>(NULL), 0)); |
| 716 CHECK(String::IsAscii(static_cast<uc16*>(NULL), 0)); | 1136 CHECK(String::IsAscii(static_cast<uc16*>(NULL), 0)); |
| 717 } | 1137 } |
| OLD | NEW |