| OLD | NEW | 
|---|
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "src/builtins/builtins.h" | 5 #include "src/builtins/builtins.h" | 
| 6 #include "src/builtins/builtins-utils.h" | 6 #include "src/builtins/builtins-utils.h" | 
| 7 | 7 | 
| 8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" | 
| 9 | 9 | 
| 10 namespace v8 { | 10 namespace v8 { | 
| 11 namespace internal { | 11 namespace internal { | 
| 12 | 12 | 
|  | 13 namespace { | 
|  | 14 | 
|  | 15 enum ResultMode { kDontNegateResult, kNegateResult }; | 
|  | 16 | 
|  | 17 void GenerateStringEqual(CodeStubAssembler* assembler, ResultMode mode) { | 
|  | 18   // Here's pseudo-code for the algorithm below in case of kDontNegateResult | 
|  | 19   // mode; for kNegateResult mode we properly negate the result. | 
|  | 20   // | 
|  | 21   // if (lhs == rhs) return true; | 
|  | 22   // if (lhs->length() != rhs->length()) return false; | 
|  | 23   // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) { | 
|  | 24   //   return false; | 
|  | 25   // } | 
|  | 26   // if (lhs->IsSeqOneByteString() && rhs->IsSeqOneByteString()) { | 
|  | 27   //   for (i = 0; i != lhs->length(); ++i) { | 
|  | 28   //     if (lhs[i] != rhs[i]) return false; | 
|  | 29   //   } | 
|  | 30   //   return true; | 
|  | 31   // } | 
|  | 32   // return %StringEqual(lhs, rhs); | 
|  | 33 | 
|  | 34   typedef CodeStubAssembler::Label Label; | 
|  | 35   typedef compiler::Node Node; | 
|  | 36   typedef CodeStubAssembler::Variable Variable; | 
|  | 37 | 
|  | 38   Node* lhs = assembler->Parameter(0); | 
|  | 39   Node* rhs = assembler->Parameter(1); | 
|  | 40   Node* context = assembler->Parameter(2); | 
|  | 41 | 
|  | 42   Label if_equal(assembler), if_notequal(assembler); | 
|  | 43 | 
|  | 44   // Fast check to see if {lhs} and {rhs} refer to the same String object. | 
|  | 45   Label if_same(assembler), if_notsame(assembler); | 
|  | 46   assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); | 
|  | 47 | 
|  | 48   assembler->Bind(&if_same); | 
|  | 49   assembler->Goto(&if_equal); | 
|  | 50 | 
|  | 51   assembler->Bind(&if_notsame); | 
|  | 52   { | 
|  | 53     // The {lhs} and {rhs} don't refer to the exact same String object. | 
|  | 54 | 
|  | 55     // Load the length of {lhs} and {rhs}. | 
|  | 56     Node* lhs_length = assembler->LoadStringLength(lhs); | 
|  | 57     Node* rhs_length = assembler->LoadStringLength(rhs); | 
|  | 58 | 
|  | 59     // Check if the lengths of {lhs} and {rhs} are equal. | 
|  | 60     Label if_lengthisequal(assembler), if_lengthisnotequal(assembler); | 
|  | 61     assembler->Branch(assembler->WordEqual(lhs_length, rhs_length), | 
|  | 62                       &if_lengthisequal, &if_lengthisnotequal); | 
|  | 63 | 
|  | 64     assembler->Bind(&if_lengthisequal); | 
|  | 65     { | 
|  | 66       // Load instance types of {lhs} and {rhs}. | 
|  | 67       Node* lhs_instance_type = assembler->LoadInstanceType(lhs); | 
|  | 68       Node* rhs_instance_type = assembler->LoadInstanceType(rhs); | 
|  | 69 | 
|  | 70       // Combine the instance types into a single 16-bit value, so we can check | 
|  | 71       // both of them at once. | 
|  | 72       Node* both_instance_types = assembler->Word32Or( | 
|  | 73           lhs_instance_type, | 
|  | 74           assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8))); | 
|  | 75 | 
|  | 76       // Check if both {lhs} and {rhs} are internalized. | 
|  | 77       int const kBothInternalizedMask = | 
|  | 78           kIsNotInternalizedMask | (kIsNotInternalizedMask << 8); | 
|  | 79       int const kBothInternalizedTag = | 
|  | 80           kInternalizedTag | (kInternalizedTag << 8); | 
|  | 81       Label if_bothinternalized(assembler), if_notbothinternalized(assembler); | 
|  | 82       assembler->Branch(assembler->Word32Equal( | 
|  | 83                             assembler->Word32And(both_instance_types, | 
|  | 84                                                  assembler->Int32Constant( | 
|  | 85                                                      kBothInternalizedMask)), | 
|  | 86                             assembler->Int32Constant(kBothInternalizedTag)), | 
|  | 87                         &if_bothinternalized, &if_notbothinternalized); | 
|  | 88 | 
|  | 89       assembler->Bind(&if_bothinternalized); | 
|  | 90       { | 
|  | 91         // Fast negative check for internalized-to-internalized equality. | 
|  | 92         assembler->Goto(&if_notequal); | 
|  | 93       } | 
|  | 94 | 
|  | 95       assembler->Bind(&if_notbothinternalized); | 
|  | 96       { | 
|  | 97         // Check that both {lhs} and {rhs} are flat one-byte strings. | 
|  | 98         int const kBothSeqOneByteStringMask = | 
|  | 99             kStringEncodingMask | kStringRepresentationMask | | 
|  | 100             ((kStringEncodingMask | kStringRepresentationMask) << 8); | 
|  | 101         int const kBothSeqOneByteStringTag = | 
|  | 102             kOneByteStringTag | kSeqStringTag | | 
|  | 103             ((kOneByteStringTag | kSeqStringTag) << 8); | 
|  | 104         Label if_bothonebyteseqstrings(assembler), | 
|  | 105             if_notbothonebyteseqstrings(assembler); | 
|  | 106         assembler->Branch( | 
|  | 107             assembler->Word32Equal( | 
|  | 108                 assembler->Word32And( | 
|  | 109                     both_instance_types, | 
|  | 110                     assembler->Int32Constant(kBothSeqOneByteStringMask)), | 
|  | 111                 assembler->Int32Constant(kBothSeqOneByteStringTag)), | 
|  | 112             &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings); | 
|  | 113 | 
|  | 114         assembler->Bind(&if_bothonebyteseqstrings); | 
|  | 115         { | 
|  | 116           // Compute the effective offset of the first character. | 
|  | 117           Node* begin = assembler->IntPtrConstant( | 
|  | 118               SeqOneByteString::kHeaderSize - kHeapObjectTag); | 
|  | 119 | 
|  | 120           // Compute the first offset after the string from the length. | 
|  | 121           Node* end = | 
|  | 122               assembler->IntPtrAdd(begin, assembler->SmiUntag(lhs_length)); | 
|  | 123 | 
|  | 124           // Loop over the {lhs} and {rhs} strings to see if they are equal. | 
|  | 125           Variable var_offset(assembler, MachineType::PointerRepresentation()); | 
|  | 126           Label loop(assembler, &var_offset); | 
|  | 127           var_offset.Bind(begin); | 
|  | 128           assembler->Goto(&loop); | 
|  | 129           assembler->Bind(&loop); | 
|  | 130           { | 
|  | 131             // Check if {offset} equals {end}. | 
|  | 132             Node* offset = var_offset.value(); | 
|  | 133             Label if_done(assembler), if_notdone(assembler); | 
|  | 134             assembler->Branch(assembler->WordEqual(offset, end), &if_done, | 
|  | 135                               &if_notdone); | 
|  | 136 | 
|  | 137             assembler->Bind(&if_notdone); | 
|  | 138             { | 
|  | 139               // Load the next characters from {lhs} and {rhs}. | 
|  | 140               Node* lhs_value = | 
|  | 141                   assembler->Load(MachineType::Uint8(), lhs, offset); | 
|  | 142               Node* rhs_value = | 
|  | 143                   assembler->Load(MachineType::Uint8(), rhs, offset); | 
|  | 144 | 
|  | 145               // Check if the characters match. | 
|  | 146               Label if_valueissame(assembler), if_valueisnotsame(assembler); | 
|  | 147               assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value), | 
|  | 148                                 &if_valueissame, &if_valueisnotsame); | 
|  | 149 | 
|  | 150               assembler->Bind(&if_valueissame); | 
|  | 151               { | 
|  | 152                 // Advance to next character. | 
|  | 153                 var_offset.Bind( | 
|  | 154                     assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1))); | 
|  | 155               } | 
|  | 156               assembler->Goto(&loop); | 
|  | 157 | 
|  | 158               assembler->Bind(&if_valueisnotsame); | 
|  | 159               assembler->Goto(&if_notequal); | 
|  | 160             } | 
|  | 161 | 
|  | 162             assembler->Bind(&if_done); | 
|  | 163             assembler->Goto(&if_equal); | 
|  | 164           } | 
|  | 165         } | 
|  | 166 | 
|  | 167         assembler->Bind(&if_notbothonebyteseqstrings); | 
|  | 168         { | 
|  | 169           // TODO(bmeurer): Add fast case support for flattened cons strings; | 
|  | 170           // also add support for two byte string equality checks. | 
|  | 171           Runtime::FunctionId function_id = (mode == kDontNegateResult) | 
|  | 172                                                 ? Runtime::kStringEqual | 
|  | 173                                                 : Runtime::kStringNotEqual; | 
|  | 174           assembler->TailCallRuntime(function_id, context, lhs, rhs); | 
|  | 175         } | 
|  | 176       } | 
|  | 177     } | 
|  | 178 | 
|  | 179     assembler->Bind(&if_lengthisnotequal); | 
|  | 180     { | 
|  | 181       // Mismatch in length of {lhs} and {rhs}, cannot be equal. | 
|  | 182       assembler->Goto(&if_notequal); | 
|  | 183     } | 
|  | 184   } | 
|  | 185 | 
|  | 186   assembler->Bind(&if_equal); | 
|  | 187   assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult)); | 
|  | 188 | 
|  | 189   assembler->Bind(&if_notequal); | 
|  | 190   assembler->Return(assembler->BooleanConstant(mode == kNegateResult)); | 
|  | 191 } | 
|  | 192 | 
|  | 193 enum RelationalComparisonMode { | 
|  | 194   kLessThan, | 
|  | 195   kLessThanOrEqual, | 
|  | 196   kGreaterThan, | 
|  | 197   kGreaterThanOrEqual | 
|  | 198 }; | 
|  | 199 | 
|  | 200 void GenerateStringRelationalComparison(CodeStubAssembler* assembler, | 
|  | 201                                         RelationalComparisonMode mode) { | 
|  | 202   typedef CodeStubAssembler::Label Label; | 
|  | 203   typedef compiler::Node Node; | 
|  | 204   typedef CodeStubAssembler::Variable Variable; | 
|  | 205 | 
|  | 206   Node* lhs = assembler->Parameter(0); | 
|  | 207   Node* rhs = assembler->Parameter(1); | 
|  | 208   Node* context = assembler->Parameter(2); | 
|  | 209 | 
|  | 210   Label if_less(assembler), if_equal(assembler), if_greater(assembler); | 
|  | 211 | 
|  | 212   // Fast check to see if {lhs} and {rhs} refer to the same String object. | 
|  | 213   Label if_same(assembler), if_notsame(assembler); | 
|  | 214   assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); | 
|  | 215 | 
|  | 216   assembler->Bind(&if_same); | 
|  | 217   assembler->Goto(&if_equal); | 
|  | 218 | 
|  | 219   assembler->Bind(&if_notsame); | 
|  | 220   { | 
|  | 221     // Load instance types of {lhs} and {rhs}. | 
|  | 222     Node* lhs_instance_type = assembler->LoadInstanceType(lhs); | 
|  | 223     Node* rhs_instance_type = assembler->LoadInstanceType(rhs); | 
|  | 224 | 
|  | 225     // Combine the instance types into a single 16-bit value, so we can check | 
|  | 226     // both of them at once. | 
|  | 227     Node* both_instance_types = assembler->Word32Or( | 
|  | 228         lhs_instance_type, | 
|  | 229         assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8))); | 
|  | 230 | 
|  | 231     // Check that both {lhs} and {rhs} are flat one-byte strings. | 
|  | 232     int const kBothSeqOneByteStringMask = | 
|  | 233         kStringEncodingMask | kStringRepresentationMask | | 
|  | 234         ((kStringEncodingMask | kStringRepresentationMask) << 8); | 
|  | 235     int const kBothSeqOneByteStringTag = | 
|  | 236         kOneByteStringTag | kSeqStringTag | | 
|  | 237         ((kOneByteStringTag | kSeqStringTag) << 8); | 
|  | 238     Label if_bothonebyteseqstrings(assembler), | 
|  | 239         if_notbothonebyteseqstrings(assembler); | 
|  | 240     assembler->Branch(assembler->Word32Equal( | 
|  | 241                           assembler->Word32And(both_instance_types, | 
|  | 242                                                assembler->Int32Constant( | 
|  | 243                                                    kBothSeqOneByteStringMask)), | 
|  | 244                           assembler->Int32Constant(kBothSeqOneByteStringTag)), | 
|  | 245                       &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings); | 
|  | 246 | 
|  | 247     assembler->Bind(&if_bothonebyteseqstrings); | 
|  | 248     { | 
|  | 249       // Load the length of {lhs} and {rhs}. | 
|  | 250       Node* lhs_length = assembler->LoadStringLength(lhs); | 
|  | 251       Node* rhs_length = assembler->LoadStringLength(rhs); | 
|  | 252 | 
|  | 253       // Determine the minimum length. | 
|  | 254       Node* length = assembler->SmiMin(lhs_length, rhs_length); | 
|  | 255 | 
|  | 256       // Compute the effective offset of the first character. | 
|  | 257       Node* begin = assembler->IntPtrConstant(SeqOneByteString::kHeaderSize - | 
|  | 258                                               kHeapObjectTag); | 
|  | 259 | 
|  | 260       // Compute the first offset after the string from the length. | 
|  | 261       Node* end = assembler->IntPtrAdd(begin, assembler->SmiUntag(length)); | 
|  | 262 | 
|  | 263       // Loop over the {lhs} and {rhs} strings to see if they are equal. | 
|  | 264       Variable var_offset(assembler, MachineType::PointerRepresentation()); | 
|  | 265       Label loop(assembler, &var_offset); | 
|  | 266       var_offset.Bind(begin); | 
|  | 267       assembler->Goto(&loop); | 
|  | 268       assembler->Bind(&loop); | 
|  | 269       { | 
|  | 270         // Check if {offset} equals {end}. | 
|  | 271         Node* offset = var_offset.value(); | 
|  | 272         Label if_done(assembler), if_notdone(assembler); | 
|  | 273         assembler->Branch(assembler->WordEqual(offset, end), &if_done, | 
|  | 274                           &if_notdone); | 
|  | 275 | 
|  | 276         assembler->Bind(&if_notdone); | 
|  | 277         { | 
|  | 278           // Load the next characters from {lhs} and {rhs}. | 
|  | 279           Node* lhs_value = assembler->Load(MachineType::Uint8(), lhs, offset); | 
|  | 280           Node* rhs_value = assembler->Load(MachineType::Uint8(), rhs, offset); | 
|  | 281 | 
|  | 282           // Check if the characters match. | 
|  | 283           Label if_valueissame(assembler), if_valueisnotsame(assembler); | 
|  | 284           assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value), | 
|  | 285                             &if_valueissame, &if_valueisnotsame); | 
|  | 286 | 
|  | 287           assembler->Bind(&if_valueissame); | 
|  | 288           { | 
|  | 289             // Advance to next character. | 
|  | 290             var_offset.Bind( | 
|  | 291                 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1))); | 
|  | 292           } | 
|  | 293           assembler->Goto(&loop); | 
|  | 294 | 
|  | 295           assembler->Bind(&if_valueisnotsame); | 
|  | 296           assembler->BranchIf(assembler->Uint32LessThan(lhs_value, rhs_value), | 
|  | 297                               &if_less, &if_greater); | 
|  | 298         } | 
|  | 299 | 
|  | 300         assembler->Bind(&if_done); | 
|  | 301         { | 
|  | 302           // All characters up to the min length are equal, decide based on | 
|  | 303           // string length. | 
|  | 304           Label if_lengthisequal(assembler), if_lengthisnotequal(assembler); | 
|  | 305           assembler->Branch(assembler->SmiEqual(lhs_length, rhs_length), | 
|  | 306                             &if_lengthisequal, &if_lengthisnotequal); | 
|  | 307 | 
|  | 308           assembler->Bind(&if_lengthisequal); | 
|  | 309           assembler->Goto(&if_equal); | 
|  | 310 | 
|  | 311           assembler->Bind(&if_lengthisnotequal); | 
|  | 312           assembler->BranchIfSmiLessThan(lhs_length, rhs_length, &if_less, | 
|  | 313                                          &if_greater); | 
|  | 314         } | 
|  | 315       } | 
|  | 316     } | 
|  | 317 | 
|  | 318     assembler->Bind(&if_notbothonebyteseqstrings); | 
|  | 319     { | 
|  | 320       // TODO(bmeurer): Add fast case support for flattened cons strings; | 
|  | 321       // also add support for two byte string relational comparisons. | 
|  | 322       switch (mode) { | 
|  | 323         case kLessThan: | 
|  | 324           assembler->TailCallRuntime(Runtime::kStringLessThan, context, lhs, | 
|  | 325                                      rhs); | 
|  | 326           break; | 
|  | 327         case kLessThanOrEqual: | 
|  | 328           assembler->TailCallRuntime(Runtime::kStringLessThanOrEqual, context, | 
|  | 329                                      lhs, rhs); | 
|  | 330           break; | 
|  | 331         case kGreaterThan: | 
|  | 332           assembler->TailCallRuntime(Runtime::kStringGreaterThan, context, lhs, | 
|  | 333                                      rhs); | 
|  | 334           break; | 
|  | 335         case kGreaterThanOrEqual: | 
|  | 336           assembler->TailCallRuntime(Runtime::kStringGreaterThanOrEqual, | 
|  | 337                                      context, lhs, rhs); | 
|  | 338           break; | 
|  | 339       } | 
|  | 340     } | 
|  | 341   } | 
|  | 342 | 
|  | 343   assembler->Bind(&if_less); | 
|  | 344   switch (mode) { | 
|  | 345     case kLessThan: | 
|  | 346     case kLessThanOrEqual: | 
|  | 347       assembler->Return(assembler->BooleanConstant(true)); | 
|  | 348       break; | 
|  | 349 | 
|  | 350     case kGreaterThan: | 
|  | 351     case kGreaterThanOrEqual: | 
|  | 352       assembler->Return(assembler->BooleanConstant(false)); | 
|  | 353       break; | 
|  | 354   } | 
|  | 355 | 
|  | 356   assembler->Bind(&if_equal); | 
|  | 357   switch (mode) { | 
|  | 358     case kLessThan: | 
|  | 359     case kGreaterThan: | 
|  | 360       assembler->Return(assembler->BooleanConstant(false)); | 
|  | 361       break; | 
|  | 362 | 
|  | 363     case kLessThanOrEqual: | 
|  | 364     case kGreaterThanOrEqual: | 
|  | 365       assembler->Return(assembler->BooleanConstant(true)); | 
|  | 366       break; | 
|  | 367   } | 
|  | 368 | 
|  | 369   assembler->Bind(&if_greater); | 
|  | 370   switch (mode) { | 
|  | 371     case kLessThan: | 
|  | 372     case kLessThanOrEqual: | 
|  | 373       assembler->Return(assembler->BooleanConstant(false)); | 
|  | 374       break; | 
|  | 375 | 
|  | 376     case kGreaterThan: | 
|  | 377     case kGreaterThanOrEqual: | 
|  | 378       assembler->Return(assembler->BooleanConstant(true)); | 
|  | 379       break; | 
|  | 380   } | 
|  | 381 } | 
|  | 382 | 
|  | 383 }  // namespace | 
|  | 384 | 
|  | 385 // static | 
|  | 386 void Builtins::Generate_StringEqual(CodeStubAssembler* assembler) { | 
|  | 387   GenerateStringEqual(assembler, kDontNegateResult); | 
|  | 388 } | 
|  | 389 | 
|  | 390 // static | 
|  | 391 void Builtins::Generate_StringNotEqual(CodeStubAssembler* assembler) { | 
|  | 392   GenerateStringEqual(assembler, kNegateResult); | 
|  | 393 } | 
|  | 394 | 
|  | 395 // static | 
|  | 396 void Builtins::Generate_StringLessThan(CodeStubAssembler* assembler) { | 
|  | 397   GenerateStringRelationalComparison(assembler, kLessThan); | 
|  | 398 } | 
|  | 399 | 
|  | 400 // static | 
|  | 401 void Builtins::Generate_StringLessThanOrEqual(CodeStubAssembler* assembler) { | 
|  | 402   GenerateStringRelationalComparison(assembler, kLessThanOrEqual); | 
|  | 403 } | 
|  | 404 | 
|  | 405 // static | 
|  | 406 void Builtins::Generate_StringGreaterThan(CodeStubAssembler* assembler) { | 
|  | 407   GenerateStringRelationalComparison(assembler, kGreaterThan); | 
|  | 408 } | 
|  | 409 | 
|  | 410 // static | 
|  | 411 void Builtins::Generate_StringGreaterThanOrEqual(CodeStubAssembler* assembler) { | 
|  | 412   GenerateStringRelationalComparison(assembler, kGreaterThanOrEqual); | 
|  | 413 } | 
|  | 414 | 
| 13 // ----------------------------------------------------------------------------- | 415 // ----------------------------------------------------------------------------- | 
| 14 // ES6 section 21.1 String Objects | 416 // ES6 section 21.1 String Objects | 
| 15 | 417 | 
| 16 // ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits ) | 418 // ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits ) | 
| 17 void Builtins::Generate_StringFromCharCode(CodeStubAssembler* assembler) { | 419 void Builtins::Generate_StringFromCharCode(CodeStubAssembler* assembler) { | 
| 18   typedef CodeStubAssembler::Label Label; | 420   typedef CodeStubAssembler::Label Label; | 
| 19   typedef compiler::Node Node; | 421   typedef compiler::Node Node; | 
| 20   typedef CodeStubAssembler::Variable Variable; | 422   typedef CodeStubAssembler::Variable Variable; | 
| 21 | 423 | 
| 22   Node* code = assembler->Parameter(1); | 424   Node* code = assembler->Parameter(1); | 
| (...skipping 542 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 565   } | 967   } | 
| 566 | 968 | 
| 567   iterator->set_string(isolate->heap()->empty_string()); | 969   iterator->set_string(isolate->heap()->empty_string()); | 
| 568 | 970 | 
| 569   return *isolate->factory()->NewJSIteratorResult( | 971   return *isolate->factory()->NewJSIteratorResult( | 
| 570       isolate->factory()->undefined_value(), true); | 972       isolate->factory()->undefined_value(), true); | 
| 571 } | 973 } | 
| 572 | 974 | 
| 573 }  // namespace internal | 975 }  // namespace internal | 
| 574 }  // namespace v8 | 976 }  // namespace v8 | 
| OLD | NEW | 
|---|