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 |