Home | History | Annotate | Download | only in cctest
      1 // Copyright 2012 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 // Check that we can traverse very deep stacks of ConsStrings using
     29 // StringCharacterStram.  Check that Get(int) works on very deep stacks
     30 // of ConsStrings.  These operations may not be very fast, but they
     31 // should be possible without getting errors due to too deep recursion.
     32 
     33 #include <stdlib.h>
     34 
     35 #include "src/v8.h"
     36 
     37 #include "src/api.h"
     38 #include "src/factory.h"
     39 #include "src/messages.h"
     40 #include "src/objects.h"
     41 #include "src/unicode-decoder.h"
     42 #include "test/cctest/cctest.h"
     43 
     44 // Adapted from http://en.wikipedia.org/wiki/Multiply-with-carry
     45 class MyRandomNumberGenerator {
     46  public:
     47   MyRandomNumberGenerator() {
     48     init();
     49   }
     50 
     51   void init(uint32_t seed = 0x5688c73e) {
     52     static const uint32_t phi = 0x9e3779b9;
     53     c = 362436;
     54     i = kQSize-1;
     55     Q[0] = seed;
     56     Q[1] = seed + phi;
     57     Q[2] = seed + phi + phi;
     58     for (unsigned j = 3; j < kQSize; j++) {
     59       Q[j] = Q[j - 3] ^ Q[j - 2] ^ phi ^ j;
     60     }
     61   }
     62 
     63   uint32_t next() {
     64     uint64_t a = 18782;
     65     uint32_t r = 0xfffffffe;
     66     i = (i + 1) & (kQSize-1);
     67     uint64_t t = a * Q[i] + c;
     68     c = (t >> 32);
     69     uint32_t x = static_cast<uint32_t>(t + c);
     70     if (x < c) {
     71       x++;
     72       c++;
     73     }
     74     return (Q[i] = r - x);
     75   }
     76 
     77   uint32_t next(int max) {
     78     return next() % max;
     79   }
     80 
     81   bool next(double threshold) {
     82     CHECK(threshold >= 0.0 && threshold <= 1.0);
     83     if (threshold == 1.0) return true;
     84     if (threshold == 0.0) return false;
     85     uint32_t value = next() % 100000;
     86     return threshold > static_cast<double>(value)/100000.0;
     87   }
     88 
     89  private:
     90   static const uint32_t kQSize = 4096;
     91   uint32_t Q[kQSize];
     92   uint32_t c;
     93   uint32_t i;
     94 };
     95 
     96 
     97 using namespace v8::internal;
     98 
     99 
    100 static const int DEEP_DEPTH = 8 * 1024;
    101 static const int SUPER_DEEP_DEPTH = 80 * 1024;
    102 
    103 
    104 class Resource: public v8::String::ExternalStringResource {
    105  public:
    106   Resource(const uc16* data, size_t length): data_(data), length_(length) {}
    107   ~Resource() { i::DeleteArray(data_); }
    108   virtual const uint16_t* data() const { return data_; }
    109   virtual size_t length() const { return length_; }
    110 
    111  private:
    112   const uc16* data_;
    113   size_t length_;
    114 };
    115 
    116 
    117 class OneByteResource : public v8::String::ExternalOneByteStringResource {
    118  public:
    119   OneByteResource(const char* data, size_t length)
    120       : data_(data), length_(length) {}
    121   ~OneByteResource() { i::DeleteArray(data_); }
    122   virtual const char* data() const { return data_; }
    123   virtual size_t length() const { return length_; }
    124 
    125  private:
    126   const char* data_;
    127   size_t length_;
    128 };
    129 
    130 
    131 static void InitializeBuildingBlocks(Handle<String>* building_blocks,
    132                                      int bb_length,
    133                                      bool long_blocks,
    134                                      MyRandomNumberGenerator* rng) {
    135   // A list of pointers that we don't have any interest in cleaning up.
    136   // If they are reachable from a root then leak detection won't complain.
    137   Isolate* isolate = CcTest::i_isolate();
    138   Factory* factory = isolate->factory();
    139   for (int i = 0; i < bb_length; i++) {
    140     int len = rng->next(16);
    141     int slice_head_chars = 0;
    142     int slice_tail_chars = 0;
    143     int slice_depth = 0;
    144     for (int j = 0; j < 3; j++) {
    145       if (rng->next(0.35)) slice_depth++;
    146     }
    147     // Must truncate something for a slice string. Loop until
    148     // at least one end will be sliced.
    149     while (slice_head_chars == 0 && slice_tail_chars == 0) {
    150       slice_head_chars = rng->next(15);
    151       slice_tail_chars = rng->next(12);
    152     }
    153     if (long_blocks) {
    154       // Generate building blocks which will never be merged
    155       len += ConsString::kMinLength + 1;
    156     } else if (len > 14) {
    157       len += 1234;
    158     }
    159     // Don't slice 0 length strings.
    160     if (len == 0) slice_depth = 0;
    161     int slice_length = slice_depth*(slice_head_chars + slice_tail_chars);
    162     len += slice_length;
    163     switch (rng->next(4)) {
    164       case 0: {
    165         uc16 buf[2000];
    166         for (int j = 0; j < len; j++) {
    167           buf[j] = rng->next(0x10000);
    168         }
    169         building_blocks[i] = factory->NewStringFromTwoByte(
    170             Vector<const uc16>(buf, len)).ToHandleChecked();
    171         for (int j = 0; j < len; j++) {
    172           CHECK_EQ(buf[j], building_blocks[i]->Get(j));
    173         }
    174         break;
    175       }
    176       case 1: {
    177         char buf[2000];
    178         for (int j = 0; j < len; j++) {
    179           buf[j] = rng->next(0x80);
    180         }
    181         building_blocks[i] = factory->NewStringFromAscii(
    182             Vector<const char>(buf, len)).ToHandleChecked();
    183         for (int j = 0; j < len; j++) {
    184           CHECK_EQ(buf[j], building_blocks[i]->Get(j));
    185         }
    186         break;
    187       }
    188       case 2: {
    189         uc16* buf = NewArray<uc16>(len);
    190         for (int j = 0; j < len; j++) {
    191           buf[j] = rng->next(0x10000);
    192         }
    193         Resource* resource = new Resource(buf, len);
    194         building_blocks[i] = v8::Utils::OpenHandle(
    195             *v8::String::NewExternalTwoByte(CcTest::isolate(), resource)
    196                  .ToLocalChecked());
    197         for (int j = 0; j < len; j++) {
    198           CHECK_EQ(buf[j], building_blocks[i]->Get(j));
    199         }
    200         break;
    201       }
    202       case 3: {
    203         char* buf = NewArray<char>(len);
    204         for (int j = 0; j < len; j++) {
    205           buf[j] = rng->next(0x80);
    206         }
    207         OneByteResource* resource = new OneByteResource(buf, len);
    208         building_blocks[i] = v8::Utils::OpenHandle(
    209             *v8::String::NewExternalOneByte(CcTest::isolate(), resource)
    210                  .ToLocalChecked());
    211         for (int j = 0; j < len; j++) {
    212           CHECK_EQ(buf[j], building_blocks[i]->Get(j));
    213         }
    214         break;
    215       }
    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);
    224   }
    225 }
    226 
    227 
    228 class ConsStringStats {
    229  public:
    230   ConsStringStats() {
    231     Reset();
    232   }
    233   void Reset();
    234   void VerifyEqual(const ConsStringStats& that) const;
    235   int leaves_;
    236   int empty_leaves_;
    237   int chars_;
    238   int left_traversals_;
    239   int right_traversals_;
    240  private:
    241   DISALLOW_COPY_AND_ASSIGN(ConsStringStats);
    242 };
    243 
    244 
    245 void ConsStringStats::Reset() {
    246   leaves_ = 0;
    247   empty_leaves_ = 0;
    248   chars_ = 0;
    249   left_traversals_ = 0;
    250   right_traversals_ = 0;
    251 }
    252 
    253 
    254 void ConsStringStats::VerifyEqual(const ConsStringStats& that) const {
    255   CHECK_EQ(this->leaves_, that.leaves_);
    256   CHECK_EQ(this->empty_leaves_, that.empty_leaves_);
    257   CHECK_EQ(this->chars_, that.chars_);
    258   CHECK_EQ(this->left_traversals_, that.left_traversals_);
    259   CHECK_EQ(this->right_traversals_, that.right_traversals_);
    260 }
    261 
    262 
    263 class ConsStringGenerationData {
    264  public:
    265   static const int kNumberOfBuildingBlocks = 256;
    266   explicit ConsStringGenerationData(bool long_blocks);
    267   void Reset();
    268   inline Handle<String> block(int offset);
    269   inline Handle<String> block(uint32_t offset);
    270   // Input variables.
    271   double early_termination_threshold_;
    272   double leftness_;
    273   double rightness_;
    274   double empty_leaf_threshold_;
    275   int max_leaves_;
    276   // Cached data.
    277   Handle<String> building_blocks_[kNumberOfBuildingBlocks];
    278   String* empty_string_;
    279   MyRandomNumberGenerator rng_;
    280   // Stats.
    281   ConsStringStats stats_;
    282   int early_terminations_;
    283  private:
    284   DISALLOW_COPY_AND_ASSIGN(ConsStringGenerationData);
    285 };
    286 
    287 
    288 ConsStringGenerationData::ConsStringGenerationData(bool long_blocks) {
    289   rng_.init();
    290   InitializeBuildingBlocks(
    291       building_blocks_, kNumberOfBuildingBlocks, long_blocks, &rng_);
    292   empty_string_ = CcTest::heap()->empty_string();
    293   Reset();
    294 }
    295 
    296 
    297 Handle<String> ConsStringGenerationData::block(uint32_t offset) {
    298   return building_blocks_[offset % kNumberOfBuildingBlocks ];
    299 }
    300 
    301 
    302 Handle<String> ConsStringGenerationData::block(int offset) {
    303   CHECK_GE(offset, 0);
    304   return building_blocks_[offset % kNumberOfBuildingBlocks];
    305 }
    306 
    307 
    308 void ConsStringGenerationData::Reset() {
    309   early_termination_threshold_ = 0.01;
    310   leftness_ = 0.75;
    311   rightness_ = 0.75;
    312   empty_leaf_threshold_ = 0.02;
    313   max_leaves_ = 1000;
    314   stats_.Reset();
    315   early_terminations_ = 0;
    316   rng_.init();
    317 }
    318 
    319 
    320 void AccumulateStats(ConsString* cons_string, ConsStringStats* stats) {
    321   int left_length = cons_string->first()->length();
    322   int right_length = cons_string->second()->length();
    323   CHECK(cons_string->length() == left_length + right_length);
    324   // Check left side.
    325   bool left_is_cons = cons_string->first()->IsConsString();
    326   if (left_is_cons) {
    327     stats->left_traversals_++;
    328     AccumulateStats(ConsString::cast(cons_string->first()), stats);
    329   } else {
    330     CHECK_NE(left_length, 0);
    331     stats->leaves_++;
    332     stats->chars_ += left_length;
    333   }
    334   // Check right side.
    335   if (cons_string->second()->IsConsString()) {
    336     stats->right_traversals_++;
    337     AccumulateStats(ConsString::cast(cons_string->second()), stats);
    338   } else {
    339     if (right_length == 0) {
    340       stats->empty_leaves_++;
    341       CHECK(!left_is_cons);
    342     }
    343     stats->leaves_++;
    344     stats->chars_ += right_length;
    345   }
    346 }
    347 
    348 
    349 void AccumulateStats(Handle<String> cons_string, ConsStringStats* stats) {
    350   DisallowHeapAllocation no_allocation;
    351   if (cons_string->IsConsString()) {
    352     return AccumulateStats(ConsString::cast(*cons_string), stats);
    353   }
    354   // This string got flattened by gc.
    355   stats->chars_ += cons_string->length();
    356 }
    357 
    358 
    359 void AccumulateStatsWithOperator(
    360     ConsString* cons_string, ConsStringStats* stats) {
    361   ConsStringIterator iter(cons_string);
    362   String* string;
    363   int offset;
    364   while (NULL != (string = iter.Next(&offset))) {
    365     // Accumulate stats.
    366     CHECK_EQ(0, offset);
    367     stats->leaves_++;
    368     stats->chars_ += string->length();
    369   }
    370 }
    371 
    372 
    373 void VerifyConsString(Handle<String> root, ConsStringGenerationData* data) {
    374   // Verify basic data.
    375   CHECK(root->IsConsString());
    376   CHECK_EQ(root->length(), data->stats_.chars_);
    377   // Recursive verify.
    378   ConsStringStats stats;
    379   AccumulateStats(ConsString::cast(*root), &stats);
    380   stats.VerifyEqual(data->stats_);
    381   // Iteratively verify.
    382   stats.Reset();
    383   AccumulateStatsWithOperator(ConsString::cast(*root), &stats);
    384   // Don't see these. Must copy over.
    385   stats.empty_leaves_ = data->stats_.empty_leaves_;
    386   stats.left_traversals_ = data->stats_.left_traversals_;
    387   stats.right_traversals_ = data->stats_.right_traversals_;
    388   // Adjust total leaves to compensate.
    389   stats.leaves_ += stats.empty_leaves_;
    390   stats.VerifyEqual(data->stats_);
    391 }
    392 
    393 
    394 static Handle<String> ConstructRandomString(ConsStringGenerationData* data,
    395                                             unsigned max_recursion) {
    396   Factory* factory = CcTest::i_isolate()->factory();
    397   // Compute termination characteristics.
    398   bool terminate = false;
    399   bool flat = data->rng_.next(data->empty_leaf_threshold_);
    400   bool terminate_early = data->rng_.next(data->early_termination_threshold_);
    401   if (terminate_early) data->early_terminations_++;
    402   // The obvious condition.
    403   terminate |= max_recursion == 0;
    404   // Flat cons string terminate by definition.
    405   terminate |= flat;
    406   // Cap for max leaves.
    407   terminate |= data->stats_.leaves_ >= data->max_leaves_;
    408   // Roll the dice.
    409   terminate |= terminate_early;
    410   // Compute termination characteristics for each side.
    411   bool terminate_left = terminate || !data->rng_.next(data->leftness_);
    412   bool terminate_right = terminate || !data->rng_.next(data->rightness_);
    413   // Generate left string.
    414   Handle<String> left;
    415   if (terminate_left) {
    416     left = data->block(data->rng_.next());
    417     data->stats_.leaves_++;
    418     data->stats_.chars_ += left->length();
    419   } else {
    420     data->stats_.left_traversals_++;
    421   }
    422   // Generate right string.
    423   Handle<String> right;
    424   if (terminate_right) {
    425     right = data->block(data->rng_.next());
    426     data->stats_.leaves_++;
    427     data->stats_.chars_ += right->length();
    428   } else {
    429     data->stats_.right_traversals_++;
    430   }
    431   // Generate the necessary sub-nodes recursively.
    432   if (!terminate_right) {
    433     // Need to balance generation fairly.
    434     if (!terminate_left && data->rng_.next(0.5)) {
    435       left = ConstructRandomString(data, max_recursion - 1);
    436     }
    437     right = ConstructRandomString(data, max_recursion - 1);
    438   }
    439   if (!terminate_left && left.is_null()) {
    440     left = ConstructRandomString(data, max_recursion - 1);
    441   }
    442   // Build the cons string.
    443   Handle<String> root = factory->NewConsString(left, right).ToHandleChecked();
    444   CHECK(root->IsConsString() && !root->IsFlat());
    445   // Special work needed for flat string.
    446   if (flat) {
    447     data->stats_.empty_leaves_++;
    448     String::Flatten(root);
    449     CHECK(root->IsConsString() && root->IsFlat());
    450   }
    451   return root;
    452 }
    453 
    454 
    455 static Handle<String> ConstructLeft(
    456     ConsStringGenerationData* data,
    457     int depth) {
    458   Factory* factory = CcTest::i_isolate()->factory();
    459   Handle<String> answer = factory->NewStringFromStaticChars("");
    460   data->stats_.leaves_++;
    461   for (int i = 0; i < depth; i++) {
    462     Handle<String> block = data->block(i);
    463     Handle<String> next =
    464         factory->NewConsString(answer, block).ToHandleChecked();
    465     if (next->IsConsString()) data->stats_.leaves_++;
    466     data->stats_.chars_ += block->length();
    467     answer = next;
    468   }
    469   data->stats_.left_traversals_ = data->stats_.leaves_ - 2;
    470   return answer;
    471 }
    472 
    473 
    474 static Handle<String> ConstructRight(
    475     ConsStringGenerationData* data,
    476     int depth) {
    477   Factory* factory = CcTest::i_isolate()->factory();
    478   Handle<String> answer = factory->NewStringFromStaticChars("");
    479   data->stats_.leaves_++;
    480   for (int i = depth - 1; i >= 0; i--) {
    481     Handle<String> block = data->block(i);
    482     Handle<String> next =
    483         factory->NewConsString(block, answer).ToHandleChecked();
    484     if (next->IsConsString()) data->stats_.leaves_++;
    485     data->stats_.chars_ += block->length();
    486     answer = next;
    487   }
    488   data->stats_.right_traversals_ = data->stats_.leaves_ - 2;
    489   return answer;
    490 }
    491 
    492 
    493 static Handle<String> ConstructBalancedHelper(
    494     ConsStringGenerationData* data,
    495     int from,
    496     int to) {
    497   Factory* factory = CcTest::i_isolate()->factory();
    498   CHECK(to > from);
    499   if (to - from == 1) {
    500     data->stats_.chars_ += data->block(from)->length();
    501     return data->block(from);
    502   }
    503   if (to - from == 2) {
    504     data->stats_.chars_ += data->block(from)->length();
    505     data->stats_.chars_ += data->block(from+1)->length();
    506     return factory->NewConsString(data->block(from), data->block(from+1))
    507         .ToHandleChecked();
    508   }
    509   Handle<String> part1 =
    510     ConstructBalancedHelper(data, from, from + ((to - from) / 2));
    511   Handle<String> part2 =
    512     ConstructBalancedHelper(data, from + ((to - from) / 2), to);
    513   if (part1->IsConsString()) data->stats_.left_traversals_++;
    514   if (part2->IsConsString()) data->stats_.right_traversals_++;
    515   return factory->NewConsString(part1, part2).ToHandleChecked();
    516 }
    517 
    518 
    519 static Handle<String> ConstructBalanced(
    520     ConsStringGenerationData* data, int depth = DEEP_DEPTH) {
    521   Handle<String> string = ConstructBalancedHelper(data, 0, depth);
    522   data->stats_.leaves_ =
    523       data->stats_.left_traversals_ + data->stats_.right_traversals_ + 2;
    524   return string;
    525 }
    526 
    527 
    528 static void Traverse(Handle<String> s1, Handle<String> s2) {
    529   int i = 0;
    530   StringCharacterStream character_stream_1(*s1);
    531   StringCharacterStream character_stream_2(*s2);
    532   while (character_stream_1.HasMore()) {
    533     CHECK(character_stream_2.HasMore());
    534     uint16_t c = character_stream_1.GetNext();
    535     CHECK_EQ(c, character_stream_2.GetNext());
    536     i++;
    537   }
    538   CHECK(!character_stream_1.HasMore());
    539   CHECK(!character_stream_2.HasMore());
    540   CHECK_EQ(s1->length(), i);
    541   CHECK_EQ(s2->length(), i);
    542 }
    543 
    544 
    545 static void TraverseFirst(Handle<String> s1, Handle<String> s2, int chars) {
    546   int i = 0;
    547   StringCharacterStream character_stream_1(*s1);
    548   StringCharacterStream character_stream_2(*s2);
    549   while (character_stream_1.HasMore() && i < chars) {
    550     CHECK(character_stream_2.HasMore());
    551     uint16_t c = character_stream_1.GetNext();
    552     CHECK_EQ(c, character_stream_2.GetNext());
    553     i++;
    554   }
    555   s1->Get(s1->length() - 1);
    556   s2->Get(s2->length() - 1);
    557 }
    558 
    559 
    560 TEST(Traverse) {
    561   printf("TestTraverse\n");
    562   CcTest::InitializeVM();
    563   v8::HandleScope scope(CcTest::isolate());
    564   ConsStringGenerationData data(false);
    565   Handle<String> flat = ConstructBalanced(&data);
    566   String::Flatten(flat);
    567   Handle<String> left_asymmetric = ConstructLeft(&data, DEEP_DEPTH);
    568   Handle<String> right_asymmetric = ConstructRight(&data, DEEP_DEPTH);
    569   Handle<String> symmetric = ConstructBalanced(&data);
    570   printf("1\n");
    571   Traverse(flat, symmetric);
    572   printf("2\n");
    573   Traverse(flat, left_asymmetric);
    574   printf("3\n");
    575   Traverse(flat, right_asymmetric);
    576   printf("4\n");
    577   Handle<String> left_deep_asymmetric =
    578       ConstructLeft(&data, SUPER_DEEP_DEPTH);
    579   Handle<String> right_deep_asymmetric =
    580       ConstructRight(&data, SUPER_DEEP_DEPTH);
    581   printf("5\n");
    582   TraverseFirst(left_asymmetric, left_deep_asymmetric, 1050);
    583   printf("6\n");
    584   TraverseFirst(left_asymmetric, right_deep_asymmetric, 65536);
    585   printf("7\n");
    586   String::Flatten(left_asymmetric);
    587   printf("10\n");
    588   Traverse(flat, left_asymmetric);
    589   printf("11\n");
    590   String::Flatten(right_asymmetric);
    591   printf("12\n");
    592   Traverse(flat, right_asymmetric);
    593   printf("14\n");
    594   String::Flatten(symmetric);
    595   printf("15\n");
    596   Traverse(flat, symmetric);
    597   printf("16\n");
    598   String::Flatten(left_deep_asymmetric);
    599   printf("18\n");
    600 }
    601 
    602 
    603 static void VerifyCharacterStream(
    604     String* flat_string, String* cons_string) {
    605   // Do not want to test ConString traversal on flat string.
    606   CHECK(flat_string->IsFlat() && !flat_string->IsConsString());
    607   CHECK(cons_string->IsConsString());
    608   // TODO(dcarney) Test stream reset as well.
    609   int length = flat_string->length();
    610   // Iterate start search in multiple places in the string.
    611   int outer_iterations = length > 20 ? 20 : length;
    612   for (int j = 0; j <= outer_iterations; j++) {
    613     int offset = length * j / outer_iterations;
    614     if (offset < 0) offset = 0;
    615     // Want to test the offset == length case.
    616     if (offset > length) offset = length;
    617     StringCharacterStream flat_stream(flat_string, offset);
    618     StringCharacterStream cons_stream(cons_string, offset);
    619     for (int i = offset; i < length; i++) {
    620       uint16_t c = flat_string->Get(i);
    621       CHECK(flat_stream.HasMore());
    622       CHECK(cons_stream.HasMore());
    623       CHECK_EQ(c, flat_stream.GetNext());
    624       CHECK_EQ(c, cons_stream.GetNext());
    625     }
    626     CHECK(!flat_stream.HasMore());
    627     CHECK(!cons_stream.HasMore());
    628   }
    629 }
    630 
    631 
    632 static inline void PrintStats(const ConsStringGenerationData& data) {
    633 #ifdef DEBUG
    634   printf("%s: [%u], %s: [%u], %s: [%u], %s: [%u], %s: [%u], %s: [%u]\n",
    635          "leaves", data.stats_.leaves_, "empty", data.stats_.empty_leaves_,
    636          "chars", data.stats_.chars_, "lefts", data.stats_.left_traversals_,
    637          "rights", data.stats_.right_traversals_, "early_terminations",
    638          data.early_terminations_);
    639 #endif
    640 }
    641 
    642 
    643 template<typename BuildString>
    644 void TestStringCharacterStream(BuildString build, int test_cases) {
    645   FLAG_gc_global = true;
    646   CcTest::InitializeVM();
    647   Isolate* isolate = CcTest::i_isolate();
    648   HandleScope outer_scope(isolate);
    649   ConsStringGenerationData data(true);
    650   for (int i = 0; i < test_cases; i++) {
    651     printf("%d\n", i);
    652     HandleScope inner_scope(isolate);
    653     AlwaysAllocateScope always_allocate(isolate);
    654     // Build flat version of cons string.
    655     Handle<String> flat_string = build(i, &data);
    656     ConsStringStats flat_string_stats;
    657     AccumulateStats(flat_string, &flat_string_stats);
    658     // Flatten string.
    659     String::Flatten(flat_string);
    660     // Build unflattened version of cons string to test.
    661     Handle<String> cons_string = build(i, &data);
    662     ConsStringStats cons_string_stats;
    663     AccumulateStats(cons_string, &cons_string_stats);
    664     DisallowHeapAllocation no_allocation;
    665     PrintStats(data);
    666     // Full verify of cons string.
    667     cons_string_stats.VerifyEqual(flat_string_stats);
    668     cons_string_stats.VerifyEqual(data.stats_);
    669     VerifyConsString(cons_string, &data);
    670     String* flat_string_ptr =
    671         flat_string->IsConsString() ?
    672         ConsString::cast(*flat_string)->first() :
    673         *flat_string;
    674     VerifyCharacterStream(flat_string_ptr, *cons_string);
    675   }
    676 }
    677 
    678 
    679 static const int kCharacterStreamNonRandomCases = 8;
    680 
    681 
    682 static Handle<String> BuildEdgeCaseConsString(
    683     int test_case, ConsStringGenerationData* data) {
    684   Factory* factory = CcTest::i_isolate()->factory();
    685   data->Reset();
    686   switch (test_case) {
    687     case 0:
    688       return ConstructBalanced(data, 71);
    689     case 1:
    690       return ConstructLeft(data, 71);
    691     case 2:
    692       return ConstructRight(data, 71);
    693     case 3:
    694       return ConstructLeft(data, 10);
    695     case 4:
    696       return ConstructRight(data, 10);
    697     case 5:
    698       // 2 element balanced tree.
    699       data->stats_.chars_ += data->block(0)->length();
    700       data->stats_.chars_ += data->block(1)->length();
    701       data->stats_.leaves_ += 2;
    702       return factory->NewConsString(data->block(0), data->block(1))
    703                  .ToHandleChecked();
    704     case 6:
    705       // Simple flattened tree.
    706       data->stats_.chars_ += data->block(0)->length();
    707       data->stats_.chars_ += data->block(1)->length();
    708       data->stats_.leaves_ += 2;
    709       data->stats_.empty_leaves_ += 1;
    710       {
    711         Handle<String> string =
    712             factory->NewConsString(data->block(0), data->block(1))
    713                 .ToHandleChecked();
    714         String::Flatten(string);
    715         return string;
    716       }
    717     case 7:
    718       // Left node flattened.
    719       data->stats_.chars_ += data->block(0)->length();
    720       data->stats_.chars_ += data->block(1)->length();
    721       data->stats_.chars_ += data->block(2)->length();
    722       data->stats_.leaves_ += 3;
    723       data->stats_.empty_leaves_ += 1;
    724       data->stats_.left_traversals_ += 1;
    725       {
    726         Handle<String> left =
    727             factory->NewConsString(data->block(0), data->block(1))
    728                 .ToHandleChecked();
    729         String::Flatten(left);
    730         return factory->NewConsString(left, data->block(2)).ToHandleChecked();
    731       }
    732     case 8:
    733       // Left node and right node flattened.
    734       data->stats_.chars_ += data->block(0)->length();
    735       data->stats_.chars_ += data->block(1)->length();
    736       data->stats_.chars_ += data->block(2)->length();
    737       data->stats_.chars_ += data->block(3)->length();
    738       data->stats_.leaves_ += 4;
    739       data->stats_.empty_leaves_ += 2;
    740       data->stats_.left_traversals_ += 1;
    741       data->stats_.right_traversals_ += 1;
    742       {
    743         Handle<String> left =
    744             factory->NewConsString(data->block(0), data->block(1))
    745                 .ToHandleChecked();
    746         String::Flatten(left);
    747         Handle<String> right =
    748             factory->NewConsString(data->block(2), data->block(2))
    749                 .ToHandleChecked();
    750         String::Flatten(right);
    751         return factory->NewConsString(left, right).ToHandleChecked();
    752       }
    753   }
    754   UNREACHABLE();
    755   return Handle<String>();
    756 }
    757 
    758 
    759 TEST(StringCharacterStreamEdgeCases) {
    760   printf("TestStringCharacterStreamEdgeCases\n");
    761   TestStringCharacterStream(
    762       BuildEdgeCaseConsString, kCharacterStreamNonRandomCases);
    763 }
    764 
    765 
    766 static const int kBalances = 3;
    767 static const int kTreeLengths = 4;
    768 static const int kEmptyLeaves = 4;
    769 static const int kUniqueRandomParameters =
    770     kBalances*kTreeLengths*kEmptyLeaves;
    771 
    772 
    773 static void InitializeGenerationData(
    774     int test_case, ConsStringGenerationData* data) {
    775   // Clear the settings and reinit the rng.
    776   data->Reset();
    777   // Spin up the rng to a known location that is unique per test.
    778   static const int kPerTestJump = 501;
    779   for (int j = 0; j < test_case*kPerTestJump; j++) {
    780     data->rng_.next();
    781   }
    782   // Choose balanced, left or right heavy trees.
    783   switch (test_case % kBalances) {
    784     case 0:
    785       // Nothing to do.  Already balanced.
    786       break;
    787     case 1:
    788       // Left balanced.
    789       data->leftness_ = 0.90;
    790       data->rightness_ = 0.15;
    791       break;
    792     case 2:
    793       // Right balanced.
    794       data->leftness_ = 0.15;
    795       data->rightness_ = 0.90;
    796       break;
    797     default:
    798       UNREACHABLE();
    799       break;
    800   }
    801   // Must remove the influence of the above decision.
    802   test_case /= kBalances;
    803   // Choose tree length.
    804   switch (test_case % kTreeLengths) {
    805     case 0:
    806       data->max_leaves_ = 16;
    807       data->early_termination_threshold_ = 0.2;
    808       break;
    809     case 1:
    810       data->max_leaves_ = 50;
    811       data->early_termination_threshold_ = 0.05;
    812       break;
    813     case 2:
    814       data->max_leaves_ = 500;
    815       data->early_termination_threshold_ = 0.03;
    816       break;
    817     case 3:
    818       data->max_leaves_ = 5000;
    819       data->early_termination_threshold_ = 0.001;
    820       break;
    821     default:
    822       UNREACHABLE();
    823       break;
    824   }
    825   // Must remove the influence of the above decision.
    826   test_case /= kTreeLengths;
    827   // Choose how much we allow empty nodes, including not at all.
    828   data->empty_leaf_threshold_ =
    829       0.03 * static_cast<double>(test_case % kEmptyLeaves);
    830 }
    831 
    832 
    833 static Handle<String> BuildRandomConsString(
    834     int test_case, ConsStringGenerationData* data) {
    835   InitializeGenerationData(test_case, data);
    836   return ConstructRandomString(data, 200);
    837 }
    838 
    839 
    840 TEST(StringCharacterStreamRandom) {
    841   printf("StringCharacterStreamRandom\n");
    842   TestStringCharacterStream(BuildRandomConsString, kUniqueRandomParameters*7);
    843 }
    844 
    845 
    846 static const int kDeepOneByteDepth = 100000;
    847 
    848 
    849 TEST(DeepOneByte) {
    850   CcTest::InitializeVM();
    851   Factory* factory = CcTest::i_isolate()->factory();
    852   v8::HandleScope scope(CcTest::isolate());
    853 
    854   char* foo = NewArray<char>(kDeepOneByteDepth);
    855   for (int i = 0; i < kDeepOneByteDepth; i++) {
    856     foo[i] = "foo "[i % 4];
    857   }
    858   Handle<String> string =
    859       factory->NewStringFromOneByte(OneByteVector(foo, kDeepOneByteDepth))
    860           .ToHandleChecked();
    861   Handle<String> foo_string = factory->NewStringFromStaticChars("foo");
    862   for (int i = 0; i < kDeepOneByteDepth; i += 10) {
    863     string = factory->NewConsString(string, foo_string).ToHandleChecked();
    864   }
    865   Handle<String> flat_string =
    866       factory->NewConsString(string, foo_string).ToHandleChecked();
    867   String::Flatten(flat_string);
    868 
    869   for (int i = 0; i < 500; i++) {
    870     TraverseFirst(flat_string, string, kDeepOneByteDepth);
    871   }
    872   DeleteArray<char>(foo);
    873 }
    874 
    875 
    876 TEST(Utf8Conversion) {
    877   // Smoke test for converting strings to utf-8.
    878   CcTest::InitializeVM();
    879   v8::HandleScope handle_scope(CcTest::isolate());
    880   // A simple one-byte string
    881   const char* one_byte_string = "abcdef12345";
    882   int len = v8::String::NewFromUtf8(CcTest::isolate(), one_byte_string,
    883                                     v8::NewStringType::kNormal,
    884                                     StrLength(one_byte_string))
    885                 .ToLocalChecked()
    886                 ->Utf8Length();
    887   CHECK_EQ(StrLength(one_byte_string), len);
    888   // A mixed one-byte and two-byte string
    889   // U+02E4 -> CB A4
    890   // U+0064 -> 64
    891   // U+12E4 -> E1 8B A4
    892   // U+0030 -> 30
    893   // U+3045 -> E3 81 85
    894   const uint16_t mixed_string[] = {0x02E4, 0x0064, 0x12E4, 0x0030, 0x3045};
    895   // The characters we expect to be output
    896   const unsigned char as_utf8[11] = {0xCB, 0xA4, 0x64, 0xE1, 0x8B, 0xA4, 0x30,
    897       0xE3, 0x81, 0x85, 0x00};
    898   // The number of bytes expected to be written for each length
    899   const int lengths[12] = {0, 0, 2, 3, 3, 3, 6, 7, 7, 7, 10, 11};
    900   const int char_lengths[12] = {0, 0, 1, 2, 2, 2, 3, 4, 4, 4, 5, 5};
    901   v8::Local<v8::String> mixed =
    902       v8::String::NewFromTwoByte(CcTest::isolate(), mixed_string,
    903                                  v8::NewStringType::kNormal, 5)
    904           .ToLocalChecked();
    905   CHECK_EQ(10, mixed->Utf8Length());
    906   // Try encoding the string with all capacities
    907   char buffer[11];
    908   const char kNoChar = static_cast<char>(-1);
    909   for (int i = 0; i <= 11; i++) {
    910     // Clear the buffer before reusing it
    911     for (int j = 0; j < 11; j++)
    912       buffer[j] = kNoChar;
    913     int chars_written;
    914     int written = mixed->WriteUtf8(buffer, i, &chars_written);
    915     CHECK_EQ(lengths[i], written);
    916     CHECK_EQ(char_lengths[i], chars_written);
    917     // Check that the contents are correct
    918     for (int j = 0; j < lengths[i]; j++)
    919       CHECK_EQ(as_utf8[j], static_cast<unsigned char>(buffer[j]));
    920     // Check that the rest of the buffer hasn't been touched
    921     for (int j = lengths[i]; j < 11; j++)
    922       CHECK_EQ(kNoChar, buffer[j]);
    923   }
    924 }
    925 
    926 
    927 TEST(ExternalShortStringAdd) {
    928   LocalContext context;
    929   v8::HandleScope handle_scope(CcTest::isolate());
    930 
    931   // Make sure we cover all always-flat lengths and at least one above.
    932   static const int kMaxLength = 20;
    933   CHECK_GT(kMaxLength, i::ConsString::kMinLength);
    934 
    935   // Allocate two JavaScript arrays for holding short strings.
    936   v8::Local<v8::Array> one_byte_external_strings =
    937       v8::Array::New(CcTest::isolate(), kMaxLength + 1);
    938   v8::Local<v8::Array> non_one_byte_external_strings =
    939       v8::Array::New(CcTest::isolate(), kMaxLength + 1);
    940 
    941   // Generate short one-byte and two-byte external strings.
    942   for (int i = 0; i <= kMaxLength; i++) {
    943     char* one_byte = NewArray<char>(i + 1);
    944     for (int j = 0; j < i; j++) {
    945       one_byte[j] = 'a';
    946     }
    947     // Terminating '\0' is left out on purpose. It is not required for external
    948     // string data.
    949     OneByteResource* one_byte_resource = new OneByteResource(one_byte, i);
    950     v8::Local<v8::String> one_byte_external_string =
    951         v8::String::NewExternalOneByte(CcTest::isolate(), one_byte_resource)
    952             .ToLocalChecked();
    953 
    954     one_byte_external_strings->Set(context.local(),
    955                                    v8::Integer::New(CcTest::isolate(), i),
    956                                    one_byte_external_string)
    957         .FromJust();
    958     uc16* non_one_byte = NewArray<uc16>(i + 1);
    959     for (int j = 0; j < i; j++) {
    960       non_one_byte[j] = 0x1234;
    961     }
    962     // Terminating '\0' is left out on purpose. It is not required for external
    963     // string data.
    964     Resource* resource = new Resource(non_one_byte, i);
    965     v8::Local<v8::String> non_one_byte_external_string =
    966         v8::String::NewExternalTwoByte(CcTest::isolate(), resource)
    967             .ToLocalChecked();
    968     non_one_byte_external_strings->Set(context.local(),
    969                                        v8::Integer::New(CcTest::isolate(), i),
    970                                        non_one_byte_external_string)
    971         .FromJust();
    972   }
    973 
    974   // Add the arrays with the short external strings in the global object.
    975   v8::Local<v8::Object> global = context->Global();
    976   global->Set(context.local(), v8_str("external_one_byte"),
    977               one_byte_external_strings)
    978       .FromJust();
    979   global->Set(context.local(), v8_str("external_non_one_byte"),
    980               non_one_byte_external_strings)
    981       .FromJust();
    982   global->Set(context.local(), v8_str("max_length"),
    983               v8::Integer::New(CcTest::isolate(), kMaxLength))
    984       .FromJust();
    985 
    986   // Add short external one-byte and two-byte strings checking the result.
    987   static const char* source =
    988       "function test() {"
    989       "  var one_byte_chars = 'aaaaaaaaaaaaaaaaaaaa';"
    990       "  var non_one_byte_chars = "
    991       "'\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1"
    992       "234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\"
    993       "u1234';"  // NOLINT
    994       "  if (one_byte_chars.length != max_length) return 1;"
    995       "  if (non_one_byte_chars.length != max_length) return 2;"
    996       "  var one_byte = Array(max_length + 1);"
    997       "  var non_one_byte = Array(max_length + 1);"
    998       "  for (var i = 0; i <= max_length; i++) {"
    999       "    one_byte[i] = one_byte_chars.substring(0, i);"
   1000       "    non_one_byte[i] = non_one_byte_chars.substring(0, i);"
   1001       "  };"
   1002       "  for (var i = 0; i <= max_length; i++) {"
   1003       "    if (one_byte[i] != external_one_byte[i]) return 3;"
   1004       "    if (non_one_byte[i] != external_non_one_byte[i]) return 4;"
   1005       "    for (var j = 0; j < i; j++) {"
   1006       "      if (external_one_byte[i] !="
   1007       "          (external_one_byte[j] + external_one_byte[i - j])) return "
   1008       "5;"
   1009       "      if (external_non_one_byte[i] !="
   1010       "          (external_non_one_byte[j] + external_non_one_byte[i - "
   1011       "j])) return 6;"
   1012       "      if (non_one_byte[i] != (non_one_byte[j] + non_one_byte[i - "
   1013       "j])) return 7;"
   1014       "      if (one_byte[i] != (one_byte[j] + one_byte[i - j])) return 8;"
   1015       "      if (one_byte[i] != (external_one_byte[j] + one_byte[i - j])) "
   1016       "return 9;"
   1017       "      if (one_byte[i] != (one_byte[j] + external_one_byte[i - j])) "
   1018       "return 10;"
   1019       "      if (non_one_byte[i] !="
   1020       "          (external_non_one_byte[j] + non_one_byte[i - j])) return "
   1021       "11;"
   1022       "      if (non_one_byte[i] !="
   1023       "          (non_one_byte[j] + external_non_one_byte[i - j])) return "
   1024       "12;"
   1025       "    }"
   1026       "  }"
   1027       "  return 0;"
   1028       "};"
   1029       "test()";
   1030   CHECK_EQ(0, CompileRun(source)->Int32Value(context.local()).FromJust());
   1031 }
   1032 
   1033 
   1034 TEST(JSONStringifySliceMadeExternal) {
   1035   CcTest::InitializeVM();
   1036   // Create a sliced string from a one-byte string.  The latter is turned
   1037   // into a two-byte external string.  Check that JSON.stringify works.
   1038   v8::HandleScope handle_scope(CcTest::isolate());
   1039   v8::Local<v8::String> underlying =
   1040       CompileRun(
   1041           "var underlying = 'abcdefghijklmnopqrstuvwxyz';"
   1042           "underlying")
   1043           ->ToString(CcTest::isolate()->GetCurrentContext())
   1044           .ToLocalChecked();
   1045   v8::Local<v8::String> slice =
   1046       CompileRun(
   1047           "var slice = '';"
   1048           "slice = underlying.slice(1);"
   1049           "slice")
   1050           ->ToString(CcTest::isolate()->GetCurrentContext())
   1051           .ToLocalChecked();
   1052   CHECK(v8::Utils::OpenHandle(*slice)->IsSlicedString());
   1053   CHECK(v8::Utils::OpenHandle(*underlying)->IsSeqOneByteString());
   1054 
   1055   int length = underlying->Length();
   1056   uc16* two_byte = NewArray<uc16>(length + 1);
   1057   underlying->Write(two_byte);
   1058   Resource* resource = new Resource(two_byte, length);
   1059   CHECK(underlying->MakeExternal(resource));
   1060   CHECK(v8::Utils::OpenHandle(*slice)->IsSlicedString());
   1061   CHECK(v8::Utils::OpenHandle(*underlying)->IsExternalTwoByteString());
   1062 
   1063   CHECK_EQ(0,
   1064            strcmp("\"bcdefghijklmnopqrstuvwxyz\"",
   1065                   *v8::String::Utf8Value(CompileRun("JSON.stringify(slice)"))));
   1066 }
   1067 
   1068 
   1069 TEST(CachedHashOverflow) {
   1070   CcTest::InitializeVM();
   1071   // We incorrectly allowed strings to be tagged as array indices even if their
   1072   // values didn't fit in the hash field.
   1073   // See http://code.google.com/p/v8/issues/detail?id=728
   1074   Isolate* isolate = CcTest::i_isolate();
   1075 
   1076   v8::HandleScope handle_scope(CcTest::isolate());
   1077   // Lines must be executed sequentially. Combining them into one script
   1078   // makes the bug go away.
   1079   const char* lines[] = {
   1080       "var x = [];",
   1081       "x[4] = 42;",
   1082       "var s = \"1073741828\";",
   1083       "x[s];",
   1084       "x[s] = 37;",
   1085       "x[4];",
   1086       "x[s];",
   1087       NULL
   1088   };
   1089 
   1090   Handle<Smi> fortytwo(Smi::FromInt(42), isolate);
   1091   Handle<Smi> thirtyseven(Smi::FromInt(37), isolate);
   1092   Handle<Object> results[] = { isolate->factory()->undefined_value(),
   1093                                fortytwo,
   1094                                isolate->factory()->undefined_value(),
   1095                                isolate->factory()->undefined_value(),
   1096                                thirtyseven,
   1097                                fortytwo,
   1098                                thirtyseven  // Bug yielded 42 here.
   1099   };
   1100 
   1101   const char* line;
   1102   v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
   1103   for (int i = 0; (line = lines[i]); i++) {
   1104     printf("%s\n", line);
   1105     v8::Local<v8::Value> result =
   1106         v8::Script::Compile(context,
   1107                             v8::String::NewFromUtf8(CcTest::isolate(), line,
   1108                                                     v8::NewStringType::kNormal)
   1109                                 .ToLocalChecked())
   1110             .ToLocalChecked()
   1111             ->Run(context)
   1112             .ToLocalChecked();
   1113     CHECK_EQ(results[i]->IsUndefined(), result->IsUndefined());
   1114     CHECK_EQ(results[i]->IsNumber(), result->IsNumber());
   1115     if (result->IsNumber()) {
   1116       int32_t value = 0;
   1117       CHECK(results[i]->ToInt32(&value));
   1118       CHECK_EQ(value, result->ToInt32(context).ToLocalChecked()->Value());
   1119     }
   1120   }
   1121 }
   1122 
   1123 
   1124 TEST(SliceFromCons) {
   1125   FLAG_string_slices = true;
   1126   CcTest::InitializeVM();
   1127   Factory* factory = CcTest::i_isolate()->factory();
   1128   v8::HandleScope scope(CcTest::isolate());
   1129   Handle<String> string =
   1130       factory->NewStringFromStaticChars("parentparentparent");
   1131   Handle<String> parent =
   1132       factory->NewConsString(string, string).ToHandleChecked();
   1133   CHECK(parent->IsConsString());
   1134   CHECK(!parent->IsFlat());
   1135   Handle<String> slice = factory->NewSubString(parent, 1, 25);
   1136   // After slicing, the original string becomes a flat cons.
   1137   CHECK(parent->IsFlat());
   1138   CHECK(slice->IsSlicedString());
   1139   CHECK_EQ(SlicedString::cast(*slice)->parent(),
   1140            // Parent could have been short-circuited.
   1141            parent->IsConsString() ? ConsString::cast(*parent)->first()
   1142                                   : *parent);
   1143   CHECK(SlicedString::cast(*slice)->parent()->IsSeqString());
   1144   CHECK(slice->IsFlat());
   1145 }
   1146 
   1147 
   1148 class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
   1149  public:
   1150   explicit OneByteVectorResource(i::Vector<const char> vector)
   1151       : data_(vector) {}
   1152   virtual ~OneByteVectorResource() {}
   1153   virtual size_t length() const { return data_.length(); }
   1154   virtual const char* data() const { return data_.start(); }
   1155  private:
   1156   i::Vector<const char> data_;
   1157 };
   1158 
   1159 
   1160 TEST(SliceFromExternal) {
   1161   FLAG_string_slices = true;
   1162   CcTest::InitializeVM();
   1163   Factory* factory = CcTest::i_isolate()->factory();
   1164   v8::HandleScope scope(CcTest::isolate());
   1165   OneByteVectorResource resource(
   1166       i::Vector<const char>("abcdefghijklmnopqrstuvwxyz", 26));
   1167   Handle<String> string =
   1168       factory->NewExternalStringFromOneByte(&resource).ToHandleChecked();
   1169   CHECK(string->IsExternalString());
   1170   Handle<String> slice = factory->NewSubString(string, 1, 25);
   1171   CHECK(slice->IsSlicedString());
   1172   CHECK(string->IsExternalString());
   1173   CHECK_EQ(SlicedString::cast(*slice)->parent(), *string);
   1174   CHECK(SlicedString::cast(*slice)->parent()->IsExternalString());
   1175   CHECK(slice->IsFlat());
   1176 }
   1177 
   1178 
   1179 TEST(TrivialSlice) {
   1180   // This tests whether a slice that contains the entire parent string
   1181   // actually creates a new string (it should not).
   1182   FLAG_string_slices = true;
   1183   CcTest::InitializeVM();
   1184   Factory* factory = CcTest::i_isolate()->factory();
   1185   v8::HandleScope scope(CcTest::isolate());
   1186   v8::Local<v8::Value> result;
   1187   Handle<String> string;
   1188   const char* init = "var str = 'abcdefghijklmnopqrstuvwxyz';";
   1189   const char* check = "str.slice(0,26)";
   1190   const char* crosscheck = "str.slice(1,25)";
   1191 
   1192   CompileRun(init);
   1193 
   1194   result = CompileRun(check);
   1195   CHECK(result->IsString());
   1196   string = v8::Utils::OpenHandle(v8::String::Cast(*result));
   1197   CHECK(!string->IsSlicedString());
   1198 
   1199   string = factory->NewSubString(string, 0, 26);
   1200   CHECK(!string->IsSlicedString());
   1201   result = CompileRun(crosscheck);
   1202   CHECK(result->IsString());
   1203   string = v8::Utils::OpenHandle(v8::String::Cast(*result));
   1204   CHECK(string->IsSlicedString());
   1205   CHECK_EQ(0, strcmp("bcdefghijklmnopqrstuvwxy", string->ToCString().get()));
   1206 }
   1207 
   1208 
   1209 TEST(SliceFromSlice) {
   1210   // This tests whether a slice that contains the entire parent string
   1211   // actually creates a new string (it should not).
   1212   FLAG_string_slices = true;
   1213   CcTest::InitializeVM();
   1214   v8::HandleScope scope(CcTest::isolate());
   1215   v8::Local<v8::Value> result;
   1216   Handle<String> string;
   1217   const char* init = "var str = 'abcdefghijklmnopqrstuvwxyz';";
   1218   const char* slice = "var slice = ''; slice = str.slice(1,-1); slice";
   1219   const char* slice_from_slice = "slice.slice(1,-1);";
   1220 
   1221   CompileRun(init);
   1222   result = CompileRun(slice);
   1223   CHECK(result->IsString());
   1224   string = v8::Utils::OpenHandle(v8::String::Cast(*result));
   1225   CHECK(string->IsSlicedString());
   1226   CHECK(SlicedString::cast(*string)->parent()->IsSeqString());
   1227   CHECK_EQ(0, strcmp("bcdefghijklmnopqrstuvwxy", string->ToCString().get()));
   1228 
   1229   result = CompileRun(slice_from_slice);
   1230   CHECK(result->IsString());
   1231   string = v8::Utils::OpenHandle(v8::String::Cast(*result));
   1232   CHECK(string->IsSlicedString());
   1233   CHECK(SlicedString::cast(*string)->parent()->IsSeqString());
   1234   CHECK_EQ(0, strcmp("cdefghijklmnopqrstuvwx", string->ToCString().get()));
   1235 }
   1236 
   1237 
   1238 UNINITIALIZED_TEST(OneByteArrayJoin) {
   1239   v8::Isolate::CreateParams create_params;
   1240   // Set heap limits.
   1241   create_params.constraints.set_max_semi_space_size(1 * Page::kPageSize / MB);
   1242   create_params.constraints.set_max_old_space_size(6 * Page::kPageSize / MB);
   1243   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
   1244   v8::Isolate* isolate = v8::Isolate::New(create_params);
   1245   isolate->Enter();
   1246 
   1247   {
   1248     // String s is made of 2^17 = 131072 'c' characters and a is an array
   1249     // starting with 'bad', followed by 2^14 times the string s. That means the
   1250     // total length of the concatenated strings is 2^31 + 3. So on 32bit systems
   1251     // summing the lengths of the strings (as Smis) overflows and wraps.
   1252     LocalContext context(isolate);
   1253     v8::HandleScope scope(isolate);
   1254     v8::TryCatch try_catch(isolate);
   1255     CHECK(CompileRun(
   1256               "var two_14 = Math.pow(2, 14);"
   1257               "var two_17 = Math.pow(2, 17);"
   1258               "var s = Array(two_17 + 1).join('c');"
   1259               "var a = ['bad'];"
   1260               "for (var i = 1; i <= two_14; i++) a.push(s);"
   1261               "a.join("
   1262               ");").IsEmpty());
   1263     CHECK(try_catch.HasCaught());
   1264   }
   1265   isolate->Exit();
   1266   isolate->Dispose();
   1267 }
   1268 
   1269 
   1270 static void CheckException(const char* source) {
   1271   // An empty handle is returned upon exception.
   1272   CHECK(CompileRun(source).IsEmpty());
   1273 }
   1274 
   1275 
   1276 TEST(RobustSubStringStub) {
   1277   // This tests whether the SubStringStub can handle unsafe arguments.
   1278   // If not recognized, those unsafe arguments lead to out-of-bounds reads.
   1279   FLAG_allow_natives_syntax = true;
   1280   CcTest::InitializeVM();
   1281   v8::HandleScope scope(CcTest::isolate());
   1282   v8::Local<v8::Value> result;
   1283   Handle<String> string;
   1284   CompileRun("var short = 'abcdef';");
   1285 
   1286   // Invalid indices.
   1287   CheckException("%_SubString(short,     0,    10000);");
   1288   CheckException("%_SubString(short, -1234,        5);");
   1289   CheckException("%_SubString(short,     5,        2);");
   1290   // Special HeapNumbers.
   1291   CheckException("%_SubString(short,     1, Infinity);");
   1292   CheckException("%_SubString(short,   NaN,        5);");
   1293   // String arguments.
   1294   CheckException("%_SubString(short,    '2',     '5');");
   1295   // Ordinary HeapNumbers can be handled (in runtime).
   1296   result = CompileRun("%_SubString(short, Math.sqrt(4), 5.1);");
   1297   string = v8::Utils::OpenHandle(v8::String::Cast(*result));
   1298   CHECK_EQ(0, strcmp("cde", string->ToCString().get()));
   1299 
   1300   CompileRun("var long = 'abcdefghijklmnopqrstuvwxyz';");
   1301   // Invalid indices.
   1302   CheckException("%_SubString(long,     0,    10000);");
   1303   CheckException("%_SubString(long, -1234,       17);");
   1304   CheckException("%_SubString(long,    17,        2);");
   1305   // Special HeapNumbers.
   1306   CheckException("%_SubString(long,     1, Infinity);");
   1307   CheckException("%_SubString(long,   NaN,       17);");
   1308   // String arguments.
   1309   CheckException("%_SubString(long,    '2',    '17');");
   1310   // Ordinary HeapNumbers within bounds can be handled (in runtime).
   1311   result = CompileRun("%_SubString(long, Math.sqrt(4), 17.1);");
   1312   string = v8::Utils::OpenHandle(v8::String::Cast(*result));
   1313   CHECK_EQ(0, strcmp("cdefghijklmnopq", string->ToCString().get()));
   1314 
   1315   // Test that out-of-bounds substring of a slice fails when the indices
   1316   // would have been valid for the underlying string.
   1317   CompileRun("var slice = long.slice(1, 15);");
   1318   CheckException("%_SubString(slice, 0, 17);");
   1319 }
   1320 
   1321 
   1322 namespace {
   1323 
   1324 int* global_use_counts = NULL;
   1325 
   1326 void MockUseCounterCallback(v8::Isolate* isolate,
   1327                             v8::Isolate::UseCounterFeature feature) {
   1328   ++global_use_counts[feature];
   1329 }
   1330 }
   1331 
   1332 
   1333 TEST(CountBreakIterator) {
   1334   CcTest::InitializeVM();
   1335   v8::HandleScope scope(CcTest::isolate());
   1336   LocalContext context;
   1337   int use_counts[v8::Isolate::kUseCounterFeatureCount] = {};
   1338   global_use_counts = use_counts;
   1339   CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback);
   1340   CHECK_EQ(0, use_counts[v8::Isolate::kBreakIterator]);
   1341   v8::Local<v8::Value> result = CompileRun(
   1342       "(function() {"
   1343       "  if (!this.Intl) return 0;"
   1344       "  var iterator = Intl.v8BreakIterator(['en']);"
   1345       "  iterator.adoptText('Now is the time');"
   1346       "  iterator.next();"
   1347       "  return iterator.next();"
   1348       "})();");
   1349   CHECK(result->IsNumber());
   1350   int uses =
   1351       result->ToInt32(context.local()).ToLocalChecked()->Value() == 0 ? 0 : 1;
   1352   CHECK_EQ(uses, use_counts[v8::Isolate::kBreakIterator]);
   1353   // Make sure GC cleans up the break iterator, so we don't get a memory leak
   1354   // reported by ASAN.
   1355   CcTest::isolate()->LowMemoryNotification();
   1356 }
   1357 
   1358 
   1359 TEST(StringReplaceAtomTwoByteResult) {
   1360   CcTest::InitializeVM();
   1361   v8::HandleScope scope(CcTest::isolate());
   1362   LocalContext context;
   1363   v8::Local<v8::Value> result = CompileRun(
   1364       "var subject = 'one_byte~only~string~'; "
   1365       "var replace = '\x80';            "
   1366       "subject.replace(/~/g, replace);  ");
   1367   CHECK(result->IsString());
   1368   Handle<String> string = v8::Utils::OpenHandle(v8::String::Cast(*result));
   1369   CHECK(string->IsSeqTwoByteString());
   1370 
   1371   v8::Local<v8::String> expected = v8_str("one_byte\x80only\x80string\x80");
   1372   CHECK(expected->Equals(context.local(), result).FromJust());
   1373 }
   1374 
   1375 
   1376 TEST(IsAscii) {
   1377   CHECK(String::IsAscii(static_cast<char*>(NULL), 0));
   1378   CHECK(String::IsOneByte(static_cast<uc16*>(NULL), 0));
   1379 }
   1380 
   1381 
   1382 
   1383 template<typename Op, bool return_first>
   1384 static uint16_t ConvertLatin1(uint16_t c) {
   1385   uint32_t result[Op::kMaxWidth];
   1386   int chars;
   1387   chars = Op::Convert(c, 0, result, NULL);
   1388   if (chars == 0) return 0;
   1389   CHECK_LE(chars, static_cast<int>(sizeof(result)));
   1390   if (!return_first && chars > 1) {
   1391     return 0;
   1392   }
   1393   return result[0];
   1394 }
   1395 
   1396 
   1397 static void CheckCanonicalEquivalence(uint16_t c, uint16_t test) {
   1398   uint16_t expect = ConvertLatin1<unibrow::Ecma262UnCanonicalize, true>(c);
   1399   if (expect > unibrow::Latin1::kMaxChar) expect = 0;
   1400   CHECK_EQ(expect, test);
   1401 }
   1402 
   1403 
   1404 TEST(Latin1IgnoreCase) {
   1405   using namespace unibrow;
   1406   for (uint16_t c = Latin1::kMaxChar + 1; c != 0; c++) {
   1407     uint16_t lower = ConvertLatin1<ToLowercase, false>(c);
   1408     uint16_t upper = ConvertLatin1<ToUppercase, false>(c);
   1409     uint16_t test = Latin1::ConvertNonLatin1ToLatin1(c);
   1410     // Filter out all character whose upper is not their lower or vice versa.
   1411     if (lower == 0 && upper == 0) {
   1412       CheckCanonicalEquivalence(c, test);
   1413       continue;
   1414     }
   1415     if (lower > Latin1::kMaxChar && upper > Latin1::kMaxChar) {
   1416       CheckCanonicalEquivalence(c, test);
   1417       continue;
   1418     }
   1419     if (lower == 0 && upper != 0) {
   1420       lower = ConvertLatin1<ToLowercase, false>(upper);
   1421     }
   1422     if (upper == 0 && lower != c) {
   1423       upper = ConvertLatin1<ToUppercase, false>(lower);
   1424     }
   1425     if (lower > Latin1::kMaxChar && upper > Latin1::kMaxChar) {
   1426       CheckCanonicalEquivalence(c, test);
   1427       continue;
   1428     }
   1429     if (upper != c && lower != c) {
   1430       CheckCanonicalEquivalence(c, test);
   1431       continue;
   1432     }
   1433     CHECK_EQ(Min(upper, lower), test);
   1434   }
   1435 }
   1436 
   1437 
   1438 class DummyResource: public v8::String::ExternalStringResource {
   1439  public:
   1440   virtual const uint16_t* data() const { return NULL; }
   1441   virtual size_t length() const { return 1 << 30; }
   1442 };
   1443 
   1444 
   1445 class DummyOneByteResource: public v8::String::ExternalOneByteStringResource {
   1446  public:
   1447   virtual const char* data() const { return NULL; }
   1448   virtual size_t length() const { return 1 << 30; }
   1449 };
   1450 
   1451 
   1452 TEST(InvalidExternalString) {
   1453   CcTest::InitializeVM();
   1454   LocalContext context;
   1455   Isolate* isolate = CcTest::i_isolate();
   1456   { HandleScope scope(isolate);
   1457     DummyOneByteResource r;
   1458     CHECK(isolate->factory()->NewExternalStringFromOneByte(&r).is_null());
   1459     CHECK(isolate->has_pending_exception());
   1460     isolate->clear_pending_exception();
   1461   }
   1462 
   1463   { HandleScope scope(isolate);
   1464     DummyResource r;
   1465     CHECK(isolate->factory()->NewExternalStringFromTwoByte(&r).is_null());
   1466     CHECK(isolate->has_pending_exception());
   1467     isolate->clear_pending_exception();
   1468   }
   1469 }
   1470 
   1471 
   1472 #define INVALID_STRING_TEST(FUN, TYPE)                                         \
   1473   TEST(StringOOM##FUN) {                                                       \
   1474     CcTest::InitializeVM();                                                    \
   1475     LocalContext context;                                                      \
   1476     Isolate* isolate = CcTest::i_isolate();                                    \
   1477     STATIC_ASSERT(String::kMaxLength < kMaxInt);                               \
   1478     static const int invalid = String::kMaxLength + 1;                         \
   1479     HandleScope scope(isolate);                                                \
   1480     Vector<TYPE> dummy = Vector<TYPE>::New(invalid);                           \
   1481     memset(dummy.start(), 0x0, dummy.length() * sizeof(TYPE));                 \
   1482     CHECK(isolate->factory()->FUN(Vector<const TYPE>::cast(dummy)).is_null()); \
   1483     memset(dummy.start(), 0x20, dummy.length() * sizeof(TYPE));                \
   1484     CHECK(isolate->has_pending_exception());                                   \
   1485     isolate->clear_pending_exception();                                        \
   1486     dummy.Dispose();                                                           \
   1487   }
   1488 
   1489 INVALID_STRING_TEST(NewStringFromAscii, char)
   1490 INVALID_STRING_TEST(NewStringFromUtf8, char)
   1491 INVALID_STRING_TEST(NewStringFromOneByte, uint8_t)
   1492 
   1493 #undef INVALID_STRING_TEST
   1494 
   1495 
   1496 TEST(FormatMessage) {
   1497   CcTest::InitializeVM();
   1498   LocalContext context;
   1499   Isolate* isolate = CcTest::i_isolate();
   1500   HandleScope scope(isolate);
   1501   Handle<String> arg0 = isolate->factory()->NewStringFromAsciiChecked("arg0");
   1502   Handle<String> arg1 = isolate->factory()->NewStringFromAsciiChecked("arg1");
   1503   Handle<String> arg2 = isolate->factory()->NewStringFromAsciiChecked("arg2");
   1504   Handle<String> result =
   1505       MessageTemplate::FormatMessage(MessageTemplate::kPropertyNotFunction,
   1506                                      arg0, arg1, arg2).ToHandleChecked();
   1507   Handle<String> expected = isolate->factory()->NewStringFromAsciiChecked(
   1508       "'arg0' returned for property 'arg1' of object 'arg2' is not a function");
   1509   CHECK(String::Equals(result, expected));
   1510 }
   1511