Chromium Code Reviews| 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-utils.h" | 5 #include "src/builtins/builtins-utils.h" |
| 6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
| 7 | 7 |
| 8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
| 9 #include "src/regexp/jsregexp.h" | 9 #include "src/regexp/jsregexp.h" |
| 10 #include "src/regexp/regexp-utils.h" | 10 #include "src/regexp/regexp-utils.h" |
| (...skipping 531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 542 Node* const proto_map = a->LoadMap(a->LoadMapPrototype(map)); | 542 Node* const proto_map = a->LoadMap(a->LoadMapPrototype(map)); |
| 543 Node* const proto_has_initialmap = | 543 Node* const proto_has_initialmap = |
| 544 a->WordEqual(proto_map, initial_proto_initial_map); | 544 a->WordEqual(proto_map, initial_proto_initial_map); |
| 545 | 545 |
| 546 // TODO(ishell): Update this check once map changes for constant field | 546 // TODO(ishell): Update this check once map changes for constant field |
| 547 // tracking are landing. | 547 // tracking are landing. |
| 548 | 548 |
| 549 a->Branch(proto_has_initialmap, if_isunmodified, if_ismodified); | 549 a->Branch(proto_has_initialmap, if_isunmodified, if_ismodified); |
| 550 } | 550 } |
| 551 | 551 |
| 552 void BranchIfFastRegExpResult(CodeStubAssembler* a, Node* context, Node* map, | |
| 553 CLabel* if_isunmodified, CLabel* if_ismodified) { | |
| 554 Node* const native_context = a->LoadNativeContext(context); | |
| 555 Node* const initial_regexp_result_map = | |
| 556 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); | |
| 557 | |
| 558 a->Branch(a->WordEqual(map, initial_regexp_result_map), if_isunmodified, | |
| 559 if_ismodified); | |
| 560 } | |
| 561 | |
| 552 } // namespace | 562 } // namespace |
| 553 | 563 |
| 554 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) { | 564 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) { |
| 555 CodeStubAssembler a(state); | 565 CodeStubAssembler a(state); |
| 556 | 566 |
| 557 Node* const receiver = a.Parameter(0); | 567 Node* const receiver = a.Parameter(0); |
| 558 Node* const context = a.Parameter(3); | 568 Node* const context = a.Parameter(3); |
| 559 | 569 |
| 560 Isolate* isolate = a.isolate(); | 570 Isolate* isolate = a.isolate(); |
| 561 Node* const int_zero = a.IntPtrConstant(0); | 571 Node* const int_zero = a.IntPtrConstant(0); |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 756 Node* FastFlagGetter(CodeStubAssembler* a, Node* const regexp, | 766 Node* FastFlagGetter(CodeStubAssembler* a, Node* const regexp, |
| 757 JSRegExp::Flag flag) { | 767 JSRegExp::Flag flag) { |
| 758 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 768 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
| 759 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 769 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
| 760 Node* const mask = a->SmiConstant(Smi::FromInt(flag)); | 770 Node* const mask = a->SmiConstant(Smi::FromInt(flag)); |
| 761 Node* const is_flag_set = a->WordNotEqual(a->WordAnd(flags, mask), smi_zero); | 771 Node* const is_flag_set = a->WordNotEqual(a->WordAnd(flags, mask), smi_zero); |
| 762 | 772 |
| 763 return is_flag_set; | 773 return is_flag_set; |
| 764 } | 774 } |
| 765 | 775 |
| 776 // Load through the GetProperty stub. | |
| 777 compiler::Node* SlowFlagGetter(CodeStubAssembler* a, | |
| 778 compiler::Node* const context, | |
| 779 compiler::Node* const regexp, | |
| 780 JSRegExp::Flag flag) { | |
| 781 Factory* factory = a->isolate()->factory(); | |
| 782 | |
| 783 CLabel out(a); | |
| 784 CVariable var_result(a, MachineType::PointerRepresentation()); | |
| 785 | |
| 786 Node* name; | |
| 787 | |
| 788 switch (flag) { | |
| 789 case JSRegExp::kGlobal: | |
| 790 name = a->HeapConstant(factory->global_string()); | |
| 791 break; | |
| 792 case JSRegExp::kIgnoreCase: | |
| 793 name = a->HeapConstant(factory->ignoreCase_string()); | |
| 794 break; | |
| 795 case JSRegExp::kMultiline: | |
| 796 name = a->HeapConstant(factory->multiline_string()); | |
| 797 break; | |
| 798 case JSRegExp::kSticky: | |
| 799 name = a->HeapConstant(factory->sticky_string()); | |
| 800 break; | |
| 801 case JSRegExp::kUnicode: | |
| 802 name = a->HeapConstant(factory->unicode_string()); | |
| 803 break; | |
| 804 default: | |
| 805 UNREACHABLE(); | |
| 806 } | |
| 807 | |
| 808 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); | |
| 809 Node* const value = a->CallStub(getproperty_callable, context, regexp, name); | |
| 810 | |
| 811 CLabel if_true(a), if_false(a); | |
| 812 a->BranchIfToBooleanIsTrue(value, &if_true, &if_false); | |
| 813 | |
| 814 a->Bind(&if_true); | |
| 815 { | |
| 816 var_result.Bind(a->IntPtrConstant(1)); | |
| 817 a->Goto(&out); | |
| 818 } | |
| 819 | |
| 820 a->Bind(&if_false); | |
| 821 { | |
| 822 var_result.Bind(a->IntPtrConstant(0)); | |
| 823 a->Goto(&out); | |
| 824 } | |
| 825 | |
| 826 a->Bind(&out); | |
| 827 return var_result.value(); | |
| 828 } | |
| 829 | |
| 766 void Generate_FlagGetter(CodeStubAssembler* a, JSRegExp::Flag flag, | 830 void Generate_FlagGetter(CodeStubAssembler* a, JSRegExp::Flag flag, |
| 767 v8::Isolate::UseCounterFeature counter, | 831 v8::Isolate::UseCounterFeature counter, |
| 768 const char* method_name) { | 832 const char* method_name) { |
| 769 Node* const receiver = a->Parameter(0); | 833 Node* const receiver = a->Parameter(0); |
| 770 Node* const context = a->Parameter(3); | 834 Node* const context = a->Parameter(3); |
| 771 | 835 |
| 772 Isolate* isolate = a->isolate(); | 836 Isolate* isolate = a->isolate(); |
| 773 | 837 |
| 774 // Check whether we have an unmodified regexp instance. | 838 // Check whether we have an unmodified regexp instance. |
| 775 CLabel if_isunmodifiedjsregexp(a), | 839 CLabel if_isunmodifiedjsregexp(a), |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1042 | 1106 |
| 1043 // Call exec. | 1107 // Call exec. |
| 1044 Node* const match_indices = RegExpExec(&a, context, receiver, string); | 1108 Node* const match_indices = RegExpExec(&a, context, receiver, string); |
| 1045 | 1109 |
| 1046 // Return true iff exec matched successfully. | 1110 // Return true iff exec matched successfully. |
| 1047 Node* const result = a.Select(a.WordEqual(match_indices, a.NullConstant()), | 1111 Node* const result = a.Select(a.WordEqual(match_indices, a.NullConstant()), |
| 1048 a.FalseConstant(), a.TrueConstant()); | 1112 a.FalseConstant(), a.TrueConstant()); |
| 1049 a.Return(result); | 1113 a.Return(result); |
| 1050 } | 1114 } |
| 1051 | 1115 |
| 1116 namespace { | |
| 1117 | |
| 1118 Node* AdvanceStringIndex(CodeStubAssembler* a, Node* const string, | |
| 1119 Node* const index, Node* const is_unicode) { | |
| 1120 CVariable var_result(a, MachineRepresentation::kTagged); | |
| 1121 | |
| 1122 // Default to last_index + 1. | |
| 1123 Node* const index_plus_one = a->SmiAdd(index, a->SmiConstant(1)); | |
| 1124 var_result.Bind(index_plus_one); | |
| 1125 | |
| 1126 CLabel if_isunicode(a), out(a); | |
| 1127 a->Branch(is_unicode, &if_isunicode, &out); | |
| 1128 | |
| 1129 a->Bind(&if_isunicode); | |
| 1130 { | |
| 1131 Node* const string_length = a->LoadStringLength(string); | |
| 1132 a->GotoUnless(a->SmiLessThan(index_plus_one, string_length), &out); | |
| 1133 | |
| 1134 Node* const lead = a->StringCharCodeAt(string, index); | |
| 1135 a->GotoUnless(a->Word32Equal(a->Word32And(lead, a->Int32Constant(0xFC00)), | |
| 1136 a->Int32Constant(0xD800)), | |
| 1137 &out); | |
| 1138 | |
| 1139 Node* const trail = a->StringCharCodeAt(string, index_plus_one); | |
| 1140 a->GotoUnless(a->Word32Equal(a->Word32And(trail, a->Int32Constant(0xFC00)), | |
| 1141 a->Int32Constant(0xDC00)), | |
| 1142 &out); | |
| 1143 | |
| 1144 // At a surrogate pair, return index + 2. | |
| 1145 Node* const index_plus_two = a->SmiAdd(index, a->SmiConstant(2)); | |
| 1146 var_result.Bind(index_plus_two); | |
| 1147 | |
| 1148 a->Goto(&out); | |
| 1149 } | |
| 1150 | |
| 1151 a->Bind(&out); | |
| 1152 return var_result.value(); | |
| 1153 } | |
| 1154 | |
| 1155 Node* NewFixedArrayCapacity(CodeStubAssembler* a, | |
| 1156 Node* const current_capacity) { | |
| 1157 CSA_ASSERT(a, a->IntPtrGreaterThan(current_capacity, a->IntPtrConstant(0))); | |
| 1158 | |
| 1159 // Growth rate is analog to JSObject::NewElementsCapacity: | |
| 1160 // new_capacity = (current_capacity + (current_capacity >> 1)) + 16. | |
| 1161 | |
| 1162 Node* const new_capacity = a->IntPtrAdd( | |
| 1163 a->IntPtrAdd(current_capacity, a->WordShr(current_capacity, 1)), | |
| 1164 a->IntPtrConstant(16)); | |
| 1165 | |
| 1166 return new_capacity; | |
| 1167 } | |
| 1168 | |
| 1169 Node* GrowFixedArray(CodeStubAssembler* a, Node* const from_array, | |
| 1170 Node* const current_capacity, Node* const new_capacity) { | |
| 1171 CSA_ASSERT(a, a->IntPtrGreaterThan(current_capacity, a->IntPtrConstant(0))); | |
| 1172 CSA_ASSERT(a, a->IntPtrGreaterThan(new_capacity, current_capacity)); | |
| 1173 | |
| 1174 ElementsKind kind = FAST_ELEMENTS; | |
| 1175 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER; | |
| 1176 CodeStubAssembler::ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | |
|
Igor Sheludko
2016/11/25 17:31:27
|mode| should be passed from outside for consisten
jgruber
2016/11/28 13:28:22
Done. Refactored growable array handling into a Gr
| |
| 1177 | |
| 1178 Node* const to_array = a->AllocateFixedArray(kind, new_capacity, mode); | |
| 1179 a->CopyFixedArrayElements(kind, from_array, kind, to_array, current_capacity, | |
| 1180 new_capacity, barrier_mode, mode); | |
| 1181 | |
| 1182 return to_array; | |
| 1183 } | |
| 1184 | |
| 1185 void Generate_RegExpPrototypeMatchBody(CodeStubAssembler* a, | |
| 1186 Node* const receiver, Node* const string, | |
| 1187 Node* const context, | |
| 1188 const bool is_fastpath) { | |
| 1189 Isolate* const isolate = a->isolate(); | |
| 1190 | |
| 1191 Node* const null = a->NullConstant(); | |
| 1192 Node* const int_zero = a->IntPtrConstant(0); | |
| 1193 Node* const smi_zero = a->SmiConstant(Smi::kZero); | |
| 1194 | |
| 1195 Node* const regexp = receiver; | |
| 1196 Node* const is_global = | |
| 1197 is_fastpath ? FastFlagGetter(a, regexp, JSRegExp::kGlobal) | |
|
Igor Sheludko
2016/11/25 17:31:27
Maybe it's worth adding FlagGetter(..., bool is_fa
jgruber
2016/11/28 13:28:22
Done.
| |
| 1198 : SlowFlagGetter(a, context, regexp, JSRegExp::kGlobal); | |
| 1199 | |
| 1200 CLabel if_isglobal(a), if_isnotglobal(a); | |
| 1201 a->Branch(is_global, &if_isglobal, &if_isnotglobal); | |
| 1202 | |
| 1203 a->Bind(&if_isnotglobal); | |
| 1204 { | |
| 1205 Node* const result = | |
| 1206 is_fastpath ? RegExpPrototypeExecInternal(a, context, regexp, string) | |
| 1207 : RegExpExec(a, context, regexp, string); | |
| 1208 a->Return(result); | |
| 1209 } | |
| 1210 | |
| 1211 a->Bind(&if_isglobal); | |
| 1212 { | |
| 1213 Node* const is_unicode = | |
| 1214 is_fastpath ? FastFlagGetter(a, regexp, JSRegExp::kUnicode) | |
| 1215 : SlowFlagGetter(a, context, regexp, JSRegExp::kUnicode); | |
| 1216 | |
| 1217 if (is_fastpath) { | |
| 1218 FastStoreLastIndex(a, context, regexp, smi_zero); | |
| 1219 } else { | |
| 1220 SlowStoreLastIndex(a, context, regexp, smi_zero); | |
| 1221 } | |
| 1222 | |
| 1223 // Allocate an array to store the resulting match strings. | |
| 1224 | |
| 1225 const ElementsKind kind = FAST_ELEMENTS; | |
| 1226 const CodeStubAssembler::ParameterMode mode = | |
| 1227 CodeStubAssembler::INTPTR_PARAMETERS; | |
| 1228 | |
| 1229 static const int kInitialArraySize = 8; | |
| 1230 Node* const initial_capacity = a->IntPtrConstant(kInitialArraySize); | |
| 1231 Node* const initial_array = | |
| 1232 a->AllocateFixedArray(kind, initial_capacity, mode); | |
| 1233 | |
| 1234 a->FillFixedArrayWithValue(kind, initial_array, int_zero, initial_capacity, | |
| 1235 Heap::kTheHoleValueRootIndex, mode); | |
| 1236 | |
| 1237 CVariable var_array(a, MachineRepresentation::kTagged); | |
| 1238 var_array.Bind(initial_array); | |
| 1239 | |
| 1240 CVariable var_array_capacity(a, MachineType::PointerRepresentation()); | |
| 1241 var_array_capacity.Bind(initial_capacity); | |
| 1242 | |
| 1243 // Loop preparations. Within the loop, collect results from RegExpExec | |
| 1244 // and store match strings in the array. | |
| 1245 | |
| 1246 CVariable var_i(a, MachineType::PointerRepresentation()); | |
| 1247 var_i.Bind(int_zero); | |
| 1248 | |
| 1249 CVariable* vars[] = {&var_i, &var_array, &var_array_capacity}; | |
| 1250 CLabel loop(a, 3, vars), loop_done(a); | |
| 1251 a->Goto(&loop); | |
| 1252 | |
| 1253 a->Bind(&loop); | |
| 1254 { | |
| 1255 Node* const i = var_i.value(); | |
| 1256 Node* const array_capacity = var_array_capacity.value(); | |
| 1257 | |
| 1258 Node* const result = | |
| 1259 is_fastpath ? RegExpPrototypeExecInternal(a, context, regexp, string) | |
| 1260 : RegExpExec(a, context, regexp, string); | |
| 1261 | |
| 1262 CLabel if_didmatch(a), if_didnotmatch(a); | |
| 1263 a->Branch(a->WordEqual(result, null), &if_didnotmatch, &if_didmatch); | |
| 1264 | |
| 1265 a->Bind(&if_didnotmatch); | |
| 1266 { | |
| 1267 // Return null if there were no matches, otherwise just exit the loop. | |
| 1268 a->GotoUnless(a->IntPtrEqual(i, int_zero), &loop_done); | |
| 1269 a->Return(null); | |
| 1270 } | |
| 1271 | |
| 1272 a->Bind(&if_didmatch); | |
| 1273 { | |
| 1274 CVariable var_match(a, MachineRepresentation::kTagged); | |
| 1275 CLabel fast_result(a), slow_result(a), match_loaded(a); | |
| 1276 BranchIfFastRegExpResult(a, context, a->LoadMap(result), &fast_result, | |
|
Igor Sheludko
2016/11/25 17:31:27
Is it possible that the RegExpPrototypeExecInterna
jgruber
2016/11/28 13:28:21
Done.
| |
| 1277 &slow_result); | |
| 1278 | |
| 1279 a->Bind(&fast_result); | |
| 1280 { | |
| 1281 // TODO(jgruber): We could optimize further here and in other | |
| 1282 // methods (e.g. @@search) by bypassing RegExp result construction. | |
| 1283 Node* const result_fixed_array = a->LoadElements(result); | |
| 1284 Node* const match = | |
| 1285 a->LoadFixedArrayElement(result_fixed_array, int_zero, 0, mode); | |
| 1286 var_match.Bind(match); | |
| 1287 a->Goto(&match_loaded); | |
| 1288 } | |
| 1289 | |
| 1290 a->Bind(&slow_result); | |
| 1291 { | |
| 1292 Node* const name = a->HeapConstant( | |
|
Igor Sheludko
2016/11/25 17:31:27
You can use SmiConstant(0) here.
| |
| 1293 isolate->factory()->NewStringFromAsciiChecked("0")); | |
| 1294 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | |
|
Igor Sheludko
2016/11/25 17:31:27
// TODO(ishell): Use GetElement stub once it's ava
jgruber
2016/11/28 13:28:21
Done.
| |
| 1295 Node* const match = | |
| 1296 a->CallStub(getproperty_callable, context, result, name); | |
| 1297 | |
| 1298 var_match.Bind(match); | |
| 1299 a->Goto(&match_loaded); | |
| 1300 } | |
| 1301 | |
| 1302 a->Bind(&match_loaded); | |
| 1303 | |
| 1304 // The match is guaranteed to be a string on the fast path. | |
|
Igor Sheludko
2016/11/25 17:31:27
CSA_ASSERT that?
jgruber
2016/11/28 13:28:22
Done.
| |
| 1305 Node* const match = is_fastpath | |
| 1306 ? var_match.value() | |
| 1307 : a->ToString(context, var_match.value()); | |
| 1308 | |
| 1309 // Store the match, growing the fixed array if needed. | |
| 1310 | |
| 1311 CLabel grow_array(a), store_match(a); | |
| 1312 a->Branch(a->IntPtrEqual(array_capacity, i), &grow_array, &store_match); | |
| 1313 | |
| 1314 a->Bind(&grow_array); | |
| 1315 { | |
| 1316 Node* const new_array_capacity = | |
| 1317 NewFixedArrayCapacity(a, array_capacity); | |
| 1318 Node* const new_array = GrowFixedArray( | |
| 1319 a, var_array.value(), array_capacity, new_array_capacity); | |
| 1320 | |
| 1321 var_array_capacity.Bind(new_array_capacity); | |
| 1322 var_array.Bind(new_array); | |
| 1323 a->Goto(&store_match); | |
| 1324 } | |
| 1325 | |
| 1326 a->Bind(&store_match); | |
| 1327 | |
| 1328 Node* const array = var_array.value(); | |
| 1329 | |
| 1330 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER; | |
| 1331 a->StoreFixedArrayElement(array, i, match, barrier_mode, 0, mode); | |
| 1332 | |
| 1333 // Increment our index counter. | |
| 1334 | |
| 1335 Node* const new_i = a->IntPtrAdd(i, a->IntPtrConstant(1)); | |
| 1336 var_i.Bind(new_i); | |
| 1337 | |
| 1338 // Advance last index if the match is the empty string. | |
| 1339 | |
| 1340 Node* const match_length = a->LoadStringLength(match); | |
| 1341 a->GotoUnless(a->SmiEqual(match_length, smi_zero), &loop); | |
| 1342 | |
| 1343 Node* last_index = is_fastpath ? FastLoadLastIndex(a, context, regexp) | |
| 1344 : SlowLoadLastIndex(a, context, regexp); | |
| 1345 | |
| 1346 Callable tolength_callable = CodeFactory::ToLength(isolate); | |
| 1347 last_index = a->CallStub(tolength_callable, context, last_index); | |
| 1348 | |
| 1349 Node* const new_last_index = | |
| 1350 AdvanceStringIndex(a, string, last_index, is_unicode); | |
| 1351 | |
| 1352 if (is_fastpath) { | |
| 1353 FastStoreLastIndex(a, context, regexp, new_last_index); | |
| 1354 } else { | |
| 1355 SlowStoreLastIndex(a, context, regexp, new_last_index); | |
| 1356 } | |
| 1357 | |
| 1358 a->Goto(&loop); | |
| 1359 } | |
| 1360 } | |
| 1361 | |
| 1362 a->Bind(&loop_done); | |
| 1363 { | |
| 1364 // Wrap the match in a JSArray. | |
| 1365 | |
| 1366 Node* const native_context = a->LoadNativeContext(context); | |
| 1367 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context); | |
| 1368 Node* const result_length = a->SmiTag(var_i.value()); | |
| 1369 Node* const result = a->AllocateUninitializedJSArrayWithoutElements( | |
| 1370 kind, array_map, result_length, nullptr); | |
| 1371 | |
| 1372 // Note: We do not currently shrink the fixed array. | |
| 1373 | |
| 1374 a->StoreObjectField(result, JSObject::kElementsOffset, var_array.value()); | |
| 1375 | |
| 1376 a->Return(result); | |
| 1377 } | |
| 1378 } | |
| 1379 } | |
| 1380 | |
| 1381 } // namespace | |
| 1382 | |
| 1052 // ES#sec-regexp.prototype-@@match | 1383 // ES#sec-regexp.prototype-@@match |
| 1053 // RegExp.prototype [ @@match ] ( string ) | 1384 // RegExp.prototype [ @@match ] ( string ) |
| 1054 BUILTIN(RegExpPrototypeMatch) { | 1385 void Builtins::Generate_RegExpPrototypeMatch(CodeAssemblerState* state) { |
| 1055 HandleScope scope(isolate); | 1386 CodeStubAssembler a(state); |
| 1056 CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.@@match"); | 1387 |
| 1057 | 1388 Node* const maybe_receiver = a.Parameter(0); |
| 1058 Handle<Object> string_obj = args.atOrUndefined(isolate, 1); | 1389 Node* const maybe_string = a.Parameter(1); |
| 1059 | 1390 Node* const context = a.Parameter(4); |
| 1060 Handle<String> string; | 1391 |
| 1061 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string, | 1392 // Ensure {maybe_receiver} is a JSReceiver. |
| 1062 Object::ToString(isolate, string_obj)); | 1393 Node* const map = ThrowIfNotJSReceiver( |
| 1063 | 1394 &a, a.isolate(), context, maybe_receiver, |
| 1064 Handle<Object> global_obj; | 1395 MessageTemplate::kIncompatibleMethodReceiver, "RegExp.prototype.@@match"); |
| 1065 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 1396 Node* const receiver = maybe_receiver; |
| 1066 isolate, global_obj, | 1397 |
| 1067 JSReceiver::GetProperty(recv, isolate->factory()->global_string())); | 1398 // Convert {maybe_string} to a String. |
| 1068 const bool global = global_obj->BooleanValue(); | 1399 Node* const string = a.ToString(context, maybe_string); |
| 1069 | 1400 |
| 1070 if (!global) { | 1401 CLabel fast_path(&a), slow_path(&a); |
| 1071 RETURN_RESULT_OR_FAILURE( | 1402 BranchIfFastPath(&a, context, map, &fast_path, &slow_path); |
| 1072 isolate, | 1403 |
| 1073 RegExpUtils::RegExpExec(isolate, recv, string, | 1404 a.Bind(&fast_path); |
| 1074 isolate->factory()->undefined_value())); | 1405 Generate_RegExpPrototypeMatchBody(&a, receiver, string, context, true); |
| 1075 } | 1406 |
| 1076 | 1407 a.Bind(&slow_path); |
| 1077 Handle<Object> unicode_obj; | 1408 Generate_RegExpPrototypeMatchBody(&a, receiver, string, context, false); |
| 1078 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 1079 isolate, unicode_obj, | |
| 1080 JSReceiver::GetProperty(recv, isolate->factory()->unicode_string())); | |
| 1081 const bool unicode = unicode_obj->BooleanValue(); | |
| 1082 | |
| 1083 RETURN_FAILURE_ON_EXCEPTION(isolate, | |
| 1084 RegExpUtils::SetLastIndex(isolate, recv, 0)); | |
| 1085 | |
| 1086 static const int kInitialArraySize = 8; | |
| 1087 Handle<FixedArray> elems = | |
| 1088 isolate->factory()->NewFixedArrayWithHoles(kInitialArraySize); | |
| 1089 | |
| 1090 int n = 0; | |
| 1091 for (;; n++) { | |
| 1092 Handle<Object> result; | |
| 1093 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 1094 isolate, result, | |
| 1095 RegExpUtils::RegExpExec(isolate, recv, string, | |
| 1096 isolate->factory()->undefined_value())); | |
| 1097 | |
| 1098 if (result->IsNull(isolate)) { | |
| 1099 if (n == 0) return isolate->heap()->null_value(); | |
| 1100 break; | |
| 1101 } | |
| 1102 | |
| 1103 Handle<Object> match_obj; | |
| 1104 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, match_obj, | |
| 1105 Object::GetElement(isolate, result, 0)); | |
| 1106 | |
| 1107 Handle<String> match; | |
| 1108 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, match, | |
| 1109 Object::ToString(isolate, match_obj)); | |
| 1110 | |
| 1111 elems = FixedArray::SetAndGrow(elems, n, match); | |
| 1112 | |
| 1113 if (match->length() == 0) { | |
| 1114 RETURN_FAILURE_ON_EXCEPTION(isolate, RegExpUtils::SetAdvancedStringIndex( | |
| 1115 isolate, recv, string, unicode)); | |
| 1116 } | |
| 1117 } | |
| 1118 | |
| 1119 elems->Shrink(n); | |
| 1120 return *isolate->factory()->NewJSArrayWithElements(elems); | |
| 1121 } | 1409 } |
| 1122 | 1410 |
| 1123 namespace { | 1411 namespace { |
| 1124 | 1412 |
| 1125 void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a, | 1413 void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a, |
| 1126 Node* const receiver, | 1414 Node* const receiver, |
| 1127 Node* const string, Node* const context, | 1415 Node* const string, Node* const context, |
| 1128 bool is_fastpath) { | 1416 bool is_fastpath) { |
| 1129 Isolate* const isolate = a->isolate(); | 1417 Isolate* const isolate = a->isolate(); |
| 1130 | 1418 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1171 { | 1459 { |
| 1172 CLabel next(a); | 1460 CLabel next(a); |
| 1173 a->GotoUnless(a->WordEqual(match_indices, a->NullConstant()), &next); | 1461 a->GotoUnless(a->WordEqual(match_indices, a->NullConstant()), &next); |
| 1174 a->Return(a->SmiConstant(-1)); | 1462 a->Return(a->SmiConstant(-1)); |
| 1175 a->Bind(&next); | 1463 a->Bind(&next); |
| 1176 } | 1464 } |
| 1177 | 1465 |
| 1178 // Return the index of the match. | 1466 // Return the index of the match. |
| 1179 { | 1467 { |
| 1180 CLabel fast_result(a), slow_result(a, CLabel::kDeferred); | 1468 CLabel fast_result(a), slow_result(a, CLabel::kDeferred); |
| 1181 | 1469 BranchIfFastRegExpResult(a, context, a->LoadMap(match_indices), |
|
Igor Sheludko
2016/11/25 17:31:27
Same here.
jgruber
2016/11/28 13:28:22
Done.
| |
| 1182 Node* const native_context = a->LoadNativeContext(context); | 1470 &fast_result, &slow_result); |
| 1183 Node* const initial_regexp_result_map = | |
| 1184 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); | |
| 1185 Node* const match_indices_map = a->LoadMap(match_indices); | |
| 1186 | |
| 1187 a->Branch(a->WordEqual(match_indices_map, initial_regexp_result_map), | |
| 1188 &fast_result, &slow_result); | |
| 1189 | 1471 |
| 1190 a->Bind(&fast_result); | 1472 a->Bind(&fast_result); |
| 1191 { | 1473 { |
| 1192 Node* const index = | 1474 Node* const index = |
| 1193 a->LoadObjectField(match_indices, JSRegExpResult::kIndexOffset, | 1475 a->LoadObjectField(match_indices, JSRegExpResult::kIndexOffset, |
| 1194 MachineType::AnyTagged()); | 1476 MachineType::AnyTagged()); |
| 1195 a->Return(index); | 1477 a->Return(index); |
| 1196 } | 1478 } |
| 1197 | 1479 |
| 1198 a->Bind(&slow_result); | 1480 a->Bind(&slow_result); |
| (...skipping 841 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2040 a.Bind(&if_matched); | 2322 a.Bind(&if_matched); |
| 2041 { | 2323 { |
| 2042 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, | 2324 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, |
| 2043 match_indices, string); | 2325 match_indices, string); |
| 2044 a.Return(result); | 2326 a.Return(result); |
| 2045 } | 2327 } |
| 2046 } | 2328 } |
| 2047 | 2329 |
| 2048 } // namespace internal | 2330 } // namespace internal |
| 2049 } // namespace v8 | 2331 } // namespace v8 |
| OLD | NEW |