| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2017 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-regexp.h" | 5 #include "src/builtins/builtins-regexp-gen.h" |
| 6 | 6 |
| 7 #include "src/builtins/builtins-constructor.h" | 7 #include "src/builtins/builtins-constructor.h" |
| 8 #include "src/builtins/builtins-utils.h" | 8 #include "src/builtins/builtins-utils-gen.h" |
| 9 #include "src/builtins/builtins.h" | 9 #include "src/builtins/builtins.h" |
| 10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
| 11 #include "src/code-stub-assembler.h" | 11 #include "src/code-stub-assembler.h" |
| 12 #include "src/counters.h" | |
| 13 #include "src/objects-inl.h" | |
| 14 #include "src/objects/regexp-match-info.h" | 12 #include "src/objects/regexp-match-info.h" |
| 15 #include "src/regexp/jsregexp.h" | 13 #include "src/regexp/regexp-macro-assembler.h" |
| 16 #include "src/regexp/regexp-utils.h" | |
| 17 #include "src/string-builder.h" | |
| 18 | 14 |
| 19 namespace v8 { | 15 namespace v8 { |
| 20 namespace internal { | 16 namespace internal { |
| 21 | 17 |
| 22 typedef CodeStubAssembler::ParameterMode ParameterMode; | 18 using compiler::Node; |
| 23 | |
| 24 | 19 |
| 25 // ----------------------------------------------------------------------------- | 20 // ----------------------------------------------------------------------------- |
| 26 // ES6 section 21.2 RegExp Objects | 21 // ES6 section 21.2 RegExp Objects |
| 27 | 22 |
| 28 Node* RegExpBuiltinsAssembler::FastLoadLastIndex(Node* regexp) { | 23 Node* RegExpBuiltinsAssembler::FastLoadLastIndex(Node* regexp) { |
| 29 // Load the in-object field. | 24 // Load the in-object field. |
| 30 static const int field_offset = | 25 static const int field_offset = |
| 31 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; | 26 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; |
| 32 return LoadObjectField(regexp, field_offset); | 27 return LoadObjectField(regexp, field_offset); |
| 33 } | 28 } |
| (...skipping 1134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1168 SmiConstant(Smi::FromInt(MessageTemplate::kRegExpNonRegExp)); | 1163 SmiConstant(Smi::FromInt(MessageTemplate::kRegExpNonRegExp)); |
| 1169 Node* const method_name_str = | 1164 Node* const method_name_str = |
| 1170 HeapConstant(isolate->factory()->NewStringFromAsciiChecked( | 1165 HeapConstant(isolate->factory()->NewStringFromAsciiChecked( |
| 1171 "RegExp.prototype.source")); | 1166 "RegExp.prototype.source")); |
| 1172 TailCallRuntime(Runtime::kThrowTypeError, context, message_id, | 1167 TailCallRuntime(Runtime::kThrowTypeError, context, message_id, |
| 1173 method_name_str); | 1168 method_name_str); |
| 1174 } | 1169 } |
| 1175 } | 1170 } |
| 1176 } | 1171 } |
| 1177 | 1172 |
| 1178 BUILTIN(RegExpPrototypeToString) { | |
| 1179 HandleScope scope(isolate); | |
| 1180 CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.toString"); | |
| 1181 | |
| 1182 if (*recv == isolate->regexp_function()->prototype()) { | |
| 1183 isolate->CountUsage(v8::Isolate::kRegExpPrototypeToString); | |
| 1184 } | |
| 1185 | |
| 1186 IncrementalStringBuilder builder(isolate); | |
| 1187 | |
| 1188 builder.AppendCharacter('/'); | |
| 1189 { | |
| 1190 Handle<Object> source; | |
| 1191 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 1192 isolate, source, | |
| 1193 JSReceiver::GetProperty(recv, isolate->factory()->source_string())); | |
| 1194 Handle<String> source_str; | |
| 1195 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, source_str, | |
| 1196 Object::ToString(isolate, source)); | |
| 1197 builder.AppendString(source_str); | |
| 1198 } | |
| 1199 | |
| 1200 builder.AppendCharacter('/'); | |
| 1201 { | |
| 1202 Handle<Object> flags; | |
| 1203 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 1204 isolate, flags, | |
| 1205 JSReceiver::GetProperty(recv, isolate->factory()->flags_string())); | |
| 1206 Handle<String> flags_str; | |
| 1207 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, flags_str, | |
| 1208 Object::ToString(isolate, flags)); | |
| 1209 builder.AppendString(flags_str); | |
| 1210 } | |
| 1211 | |
| 1212 RETURN_RESULT_OR_FAILURE(isolate, builder.Finish()); | |
| 1213 } | |
| 1214 | |
| 1215 // Fast-path implementation for flag checks on an unmodified JSRegExp instance. | 1173 // Fast-path implementation for flag checks on an unmodified JSRegExp instance. |
| 1216 Node* RegExpBuiltinsAssembler::FastFlagGetter(Node* const regexp, | 1174 Node* RegExpBuiltinsAssembler::FastFlagGetter(Node* const regexp, |
| 1217 JSRegExp::Flag flag) { | 1175 JSRegExp::Flag flag) { |
| 1218 Node* const smi_zero = SmiConstant(Smi::kZero); | 1176 Node* const smi_zero = SmiConstant(Smi::kZero); |
| 1219 Node* const flags = LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 1177 Node* const flags = LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
| 1220 Node* const mask = SmiConstant(Smi::FromInt(flag)); | 1178 Node* const mask = SmiConstant(Smi::FromInt(flag)); |
| 1221 Node* const is_flag_set = WordNotEqual(SmiAnd(flags, mask), smi_zero); | 1179 Node* const is_flag_set = WordNotEqual(SmiAnd(flags, mask), smi_zero); |
| 1222 | 1180 |
| 1223 return is_flag_set; | 1181 return is_flag_set; |
| 1224 } | 1182 } |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1365 FlagGetter(JSRegExp::kSticky, v8::Isolate::kRegExpPrototypeStickyGetter, | 1323 FlagGetter(JSRegExp::kSticky, v8::Isolate::kRegExpPrototypeStickyGetter, |
| 1366 "RegExp.prototype.sticky"); | 1324 "RegExp.prototype.sticky"); |
| 1367 } | 1325 } |
| 1368 | 1326 |
| 1369 // ES6 21.2.5.15. | 1327 // ES6 21.2.5.15. |
| 1370 TF_BUILTIN(RegExpPrototypeUnicodeGetter, RegExpBuiltinsAssembler) { | 1328 TF_BUILTIN(RegExpPrototypeUnicodeGetter, RegExpBuiltinsAssembler) { |
| 1371 FlagGetter(JSRegExp::kUnicode, v8::Isolate::kRegExpPrototypeUnicodeGetter, | 1329 FlagGetter(JSRegExp::kUnicode, v8::Isolate::kRegExpPrototypeUnicodeGetter, |
| 1372 "RegExp.prototype.unicode"); | 1330 "RegExp.prototype.unicode"); |
| 1373 } | 1331 } |
| 1374 | 1332 |
| 1375 // The properties $1..$9 are the first nine capturing substrings of the last | |
| 1376 // successful match, or ''. The function RegExpMakeCaptureGetter will be | |
| 1377 // called with indices from 1 to 9. | |
| 1378 #define DEFINE_CAPTURE_GETTER(i) \ | |
| 1379 BUILTIN(RegExpCapture##i##Getter) { \ | |
| 1380 HandleScope scope(isolate); \ | |
| 1381 return *RegExpUtils::GenericCaptureGetter( \ | |
| 1382 isolate, isolate->regexp_last_match_info(), i); \ | |
| 1383 } | |
| 1384 DEFINE_CAPTURE_GETTER(1) | |
| 1385 DEFINE_CAPTURE_GETTER(2) | |
| 1386 DEFINE_CAPTURE_GETTER(3) | |
| 1387 DEFINE_CAPTURE_GETTER(4) | |
| 1388 DEFINE_CAPTURE_GETTER(5) | |
| 1389 DEFINE_CAPTURE_GETTER(6) | |
| 1390 DEFINE_CAPTURE_GETTER(7) | |
| 1391 DEFINE_CAPTURE_GETTER(8) | |
| 1392 DEFINE_CAPTURE_GETTER(9) | |
| 1393 #undef DEFINE_CAPTURE_GETTER | |
| 1394 | |
| 1395 // The properties `input` and `$_` are aliases for each other. When this | |
| 1396 // value is set, the value it is set to is coerced to a string. | |
| 1397 // Getter and setter for the input. | |
| 1398 | |
| 1399 BUILTIN(RegExpInputGetter) { | |
| 1400 HandleScope scope(isolate); | |
| 1401 Handle<Object> obj(isolate->regexp_last_match_info()->LastInput(), isolate); | |
| 1402 return obj->IsUndefined(isolate) ? isolate->heap()->empty_string() | |
| 1403 : String::cast(*obj); | |
| 1404 } | |
| 1405 | |
| 1406 BUILTIN(RegExpInputSetter) { | |
| 1407 HandleScope scope(isolate); | |
| 1408 Handle<Object> value = args.atOrUndefined(isolate, 1); | |
| 1409 Handle<String> str; | |
| 1410 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, str, | |
| 1411 Object::ToString(isolate, value)); | |
| 1412 isolate->regexp_last_match_info()->SetLastInput(*str); | |
| 1413 return isolate->heap()->undefined_value(); | |
| 1414 } | |
| 1415 | |
| 1416 // Getters for the static properties lastMatch, lastParen, leftContext, and | |
| 1417 // rightContext of the RegExp constructor. The properties are computed based | |
| 1418 // on the captures array of the last successful match and the subject string | |
| 1419 // of the last successful match. | |
| 1420 BUILTIN(RegExpLastMatchGetter) { | |
| 1421 HandleScope scope(isolate); | |
| 1422 return *RegExpUtils::GenericCaptureGetter( | |
| 1423 isolate, isolate->regexp_last_match_info(), 0); | |
| 1424 } | |
| 1425 | |
| 1426 BUILTIN(RegExpLastParenGetter) { | |
| 1427 HandleScope scope(isolate); | |
| 1428 Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info(); | |
| 1429 const int length = match_info->NumberOfCaptureRegisters(); | |
| 1430 if (length <= 2) return isolate->heap()->empty_string(); // No captures. | |
| 1431 | |
| 1432 DCHECK_EQ(0, length % 2); | |
| 1433 const int last_capture = (length / 2) - 1; | |
| 1434 | |
| 1435 // We match the SpiderMonkey behavior: return the substring defined by the | |
| 1436 // last pair (after the first pair) of elements of the capture array even if | |
| 1437 // it is empty. | |
| 1438 return *RegExpUtils::GenericCaptureGetter(isolate, match_info, last_capture); | |
| 1439 } | |
| 1440 | |
| 1441 BUILTIN(RegExpLeftContextGetter) { | |
| 1442 HandleScope scope(isolate); | |
| 1443 Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info(); | |
| 1444 const int start_index = match_info->Capture(0); | |
| 1445 Handle<String> last_subject(match_info->LastSubject()); | |
| 1446 return *isolate->factory()->NewSubString(last_subject, 0, start_index); | |
| 1447 } | |
| 1448 | |
| 1449 BUILTIN(RegExpRightContextGetter) { | |
| 1450 HandleScope scope(isolate); | |
| 1451 Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info(); | |
| 1452 const int start_index = match_info->Capture(1); | |
| 1453 Handle<String> last_subject(match_info->LastSubject()); | |
| 1454 const int len = last_subject->length(); | |
| 1455 return *isolate->factory()->NewSubString(last_subject, start_index, len); | |
| 1456 } | |
| 1457 | |
| 1458 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) | 1333 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) |
| 1459 Node* RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp, | 1334 Node* RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp, |
| 1460 Node* string) { | 1335 Node* string) { |
| 1461 Isolate* isolate = this->isolate(); | 1336 Isolate* isolate = this->isolate(); |
| 1462 | 1337 |
| 1463 Node* const null = NullConstant(); | 1338 Node* const null = NullConstant(); |
| 1464 | 1339 |
| 1465 Variable var_result(this, MachineRepresentation::kTagged); | 1340 Variable var_result(this, MachineRepresentation::kTagged); |
| 1466 Label out(this), if_isfastpath(this), if_isslowpath(this); | 1341 Label out(this), if_isfastpath(this), if_isslowpath(this); |
| 1467 | 1342 |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1722 // {element_count} elements from the current array. | 1597 // {element_count} elements from the current array. |
| 1723 Node* ResizeFixedArray(Node* const element_count, Node* const new_capacity) { | 1598 Node* ResizeFixedArray(Node* const element_count, Node* const new_capacity) { |
| 1724 CodeStubAssembler* a = assembler_; | 1599 CodeStubAssembler* a = assembler_; |
| 1725 | 1600 |
| 1726 CSA_ASSERT(a, a->IntPtrGreaterThan(element_count, a->IntPtrConstant(0))); | 1601 CSA_ASSERT(a, a->IntPtrGreaterThan(element_count, a->IntPtrConstant(0))); |
| 1727 CSA_ASSERT(a, a->IntPtrGreaterThan(new_capacity, a->IntPtrConstant(0))); | 1602 CSA_ASSERT(a, a->IntPtrGreaterThan(new_capacity, a->IntPtrConstant(0))); |
| 1728 CSA_ASSERT(a, a->IntPtrGreaterThanOrEqual(new_capacity, element_count)); | 1603 CSA_ASSERT(a, a->IntPtrGreaterThanOrEqual(new_capacity, element_count)); |
| 1729 | 1604 |
| 1730 const ElementsKind kind = FAST_ELEMENTS; | 1605 const ElementsKind kind = FAST_ELEMENTS; |
| 1731 const WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER; | 1606 const WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER; |
| 1732 const ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | 1607 const CodeStubAssembler::ParameterMode mode = |
| 1608 CodeStubAssembler::INTPTR_PARAMETERS; |
| 1733 const CodeStubAssembler::AllocationFlags flags = | 1609 const CodeStubAssembler::AllocationFlags flags = |
| 1734 CodeStubAssembler::kAllowLargeObjectAllocation; | 1610 CodeStubAssembler::kAllowLargeObjectAllocation; |
| 1735 | 1611 |
| 1736 Node* const from_array = var_array_.value(); | 1612 Node* const from_array = var_array_.value(); |
| 1737 Node* const to_array = | 1613 Node* const to_array = |
| 1738 a->AllocateFixedArray(kind, new_capacity, mode, flags); | 1614 a->AllocateFixedArray(kind, new_capacity, mode, flags); |
| 1739 a->CopyFixedArrayElements(kind, from_array, kind, to_array, element_count, | 1615 a->CopyFixedArrayElements(kind, from_array, kind, to_array, element_count, |
| 1740 new_capacity, barrier_mode, mode); | 1616 new_capacity, barrier_mode, mode); |
| 1741 | 1617 |
| 1742 return to_array; | 1618 return to_array; |
| (...skipping 764 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2507 } | 2383 } |
| 2508 } | 2384 } |
| 2509 } | 2385 } |
| 2510 | 2386 |
| 2511 Bind(&if_hasexplicitcaptures); | 2387 Bind(&if_hasexplicitcaptures); |
| 2512 { | 2388 { |
| 2513 Node* const from = int_zero; | 2389 Node* const from = int_zero; |
| 2514 Node* const to = SmiUntag(res_length); | 2390 Node* const to = SmiUntag(res_length); |
| 2515 const int increment = 1; | 2391 const int increment = 1; |
| 2516 | 2392 |
| 2517 BuildFastLoop( | 2393 BuildFastLoop(from, to, |
| 2518 from, to, | 2394 [this, res_elems, isolate, native_context, context, undefined, |
| 2519 [this, res_elems, isolate, native_context, context, undefined, | 2395 replace_callable](Node* index) { |
| 2520 replace_callable](Node* index) { | 2396 Node* const elem = LoadFixedArrayElement(res_elems, index); |
| 2521 Node* const elem = LoadFixedArrayElement(res_elems, index); | |
| 2522 | 2397 |
| 2523 Label do_continue(this); | 2398 Label do_continue(this); |
| 2524 GotoIf(TaggedIsSmi(elem), &do_continue); | 2399 GotoIf(TaggedIsSmi(elem), &do_continue); |
| 2525 | 2400 |
| 2526 // elem must be an Array. | 2401 // elem must be an Array. |
| 2527 // Use the apply argument as backing for global RegExp properties. | 2402 // Use the apply argument as backing for global RegExp |
| 2403 // properties. |
| 2528 | 2404 |
| 2529 CSA_ASSERT(this, HasInstanceType(elem, JS_ARRAY_TYPE)); | 2405 CSA_ASSERT(this, HasInstanceType(elem, JS_ARRAY_TYPE)); |
| 2530 | 2406 |
| 2531 // TODO(jgruber): Remove indirection through Call->ReflectApply. | 2407 // TODO(jgruber): Remove indirection through |
| 2532 Callable call_callable = CodeFactory::Call(isolate); | 2408 // Call->ReflectApply. |
| 2533 Node* const reflect_apply = | 2409 Callable call_callable = CodeFactory::Call(isolate); |
| 2534 LoadContextElement(native_context, Context::REFLECT_APPLY_INDEX); | 2410 Node* const reflect_apply = LoadContextElement( |
| 2411 native_context, Context::REFLECT_APPLY_INDEX); |
| 2535 | 2412 |
| 2536 Node* const replacement_obj = | 2413 Node* const replacement_obj = |
| 2537 CallJS(call_callable, context, reflect_apply, undefined, | 2414 CallJS(call_callable, context, reflect_apply, undefined, |
| 2538 replace_callable, undefined, elem); | 2415 replace_callable, undefined, elem); |
| 2539 | 2416 |
| 2540 // Overwrite the i'th element in the results with the string we got | 2417 // Overwrite the i'th element in the results with the string |
| 2541 // back from the callback function. | 2418 // we got back from the callback function. |
| 2542 | 2419 |
| 2543 Node* const replacement_str = ToString(context, replacement_obj); | 2420 Node* const replacement_str = |
| 2544 StoreFixedArrayElement(res_elems, index, replacement_str); | 2421 ToString(context, replacement_obj); |
| 2422 StoreFixedArrayElement(res_elems, index, replacement_str); |
| 2545 | 2423 |
| 2546 Goto(&do_continue); | 2424 Goto(&do_continue); |
| 2547 Bind(&do_continue); | 2425 Bind(&do_continue); |
| 2548 }, | 2426 }, |
| 2549 increment, CodeStubAssembler::INTPTR_PARAMETERS, | 2427 increment, CodeStubAssembler::INTPTR_PARAMETERS, |
| 2550 CodeStubAssembler::IndexAdvanceMode::kPost); | 2428 CodeStubAssembler::IndexAdvanceMode::kPost); |
| 2551 | 2429 |
| 2552 Goto(&create_result); | 2430 Goto(&create_result); |
| 2553 } | 2431 } |
| 2554 | 2432 |
| 2555 Bind(&create_result); | 2433 Bind(&create_result); |
| 2556 { | 2434 { |
| 2557 Node* const result = CallRuntime(Runtime::kStringBuilderConcat, context, | 2435 Node* const result = CallRuntime(Runtime::kStringBuilderConcat, context, |
| 2558 res, res_length, string); | 2436 res, res_length, string); |
| 2559 var_result.Bind(result); | 2437 var_result.Bind(result); |
| 2560 Goto(&out); | 2438 Goto(&out); |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2800 Bind(&if_matched); | 2678 Bind(&if_matched); |
| 2801 { | 2679 { |
| 2802 Node* result = | 2680 Node* result = |
| 2803 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); | 2681 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); |
| 2804 Return(result); | 2682 Return(result); |
| 2805 } | 2683 } |
| 2806 } | 2684 } |
| 2807 | 2685 |
| 2808 } // namespace internal | 2686 } // namespace internal |
| 2809 } // namespace v8 | 2687 } // namespace v8 |
| OLD | NEW |