Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(103)

Side by Side Diff: test/cctest/test-strings.cc

Issue 11438046: Cleanup StringCharacterStream and add initial test cases. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: SlicedStrings added to tests Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/objects-inl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « src/objects-inl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698