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 | 10 |
11 namespace v8 { | 11 namespace v8 { |
12 namespace internal { | 12 namespace internal { |
13 | 13 |
| 14 // ----------------------------------------------------------------------------- |
| 15 // ES6 section 21.2 RegExp Objects |
| 16 |
| 17 namespace { |
| 18 |
| 19 // ES#sec-isregexp IsRegExp ( argument ) |
| 20 Maybe<bool> IsRegExp(Isolate* isolate, Handle<Object> object) { |
| 21 if (!object->IsJSReceiver()) return Just(false); |
| 22 |
| 23 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object); |
| 24 |
| 25 if (isolate->regexp_function()->initial_map() == receiver->map()) { |
| 26 // Fast-path for unmodified JSRegExp instances. |
| 27 return Just(true); |
| 28 } |
| 29 |
| 30 Handle<Object> match; |
| 31 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 32 isolate, match, |
| 33 JSObject::GetProperty(receiver, isolate->factory()->match_symbol()), |
| 34 Nothing<bool>()); |
| 35 |
| 36 if (!match->IsUndefined(isolate)) return Just(match->BooleanValue()); |
| 37 return Just(object->IsJSRegExp()); |
| 38 } |
| 39 |
| 40 Handle<String> PatternFlags(Isolate* isolate, Handle<JSRegExp> regexp) { |
| 41 static const int kMaxFlagsLength = 5 + 1; // 5 flags and '\0'; |
| 42 char flags_string[kMaxFlagsLength]; |
| 43 int i = 0; |
| 44 |
| 45 const JSRegExp::Flags flags = regexp->GetFlags(); |
| 46 |
| 47 if ((flags & JSRegExp::kGlobal) != 0) flags_string[i++] = 'g'; |
| 48 if ((flags & JSRegExp::kIgnoreCase) != 0) flags_string[i++] = 'i'; |
| 49 if ((flags & JSRegExp::kMultiline) != 0) flags_string[i++] = 'm'; |
| 50 if ((flags & JSRegExp::kUnicode) != 0) flags_string[i++] = 'u'; |
| 51 if ((flags & JSRegExp::kSticky) != 0) flags_string[i++] = 'y'; |
| 52 |
| 53 DCHECK_LT(i, kMaxFlagsLength); |
| 54 memset(&flags_string[i], '\0', kMaxFlagsLength - i); |
| 55 |
| 56 return isolate->factory()->NewStringFromAsciiChecked(flags_string); |
| 57 } |
| 58 |
| 59 // ES#sec-regexpinitialize |
| 60 // Runtime Semantics: RegExpInitialize ( obj, pattern, flags ) |
| 61 MaybeHandle<JSRegExp> RegExpInitialize(Isolate* isolate, |
| 62 Handle<JSRegExp> regexp, |
| 63 Handle<Object> pattern, |
| 64 Handle<Object> flags) { |
| 65 Handle<String> pattern_string; |
| 66 if (pattern->IsUndefined(isolate)) { |
| 67 pattern_string = isolate->factory()->empty_string(); |
| 68 } else { |
| 69 ASSIGN_RETURN_ON_EXCEPTION(isolate, pattern_string, |
| 70 Object::ToString(isolate, pattern), JSRegExp); |
| 71 } |
| 72 |
| 73 Handle<String> flags_string; |
| 74 if (flags->IsUndefined(isolate)) { |
| 75 flags_string = isolate->factory()->empty_string(); |
| 76 } else { |
| 77 ASSIGN_RETURN_ON_EXCEPTION(isolate, flags_string, |
| 78 Object::ToString(isolate, flags), JSRegExp); |
| 79 } |
| 80 |
| 81 // TODO(jgruber): We could avoid the flags back and forth conversions. |
| 82 RETURN_RESULT(isolate, |
| 83 JSRegExp::Initialize(regexp, pattern_string, flags_string), |
| 84 JSRegExp); |
| 85 } |
| 86 |
| 87 } // namespace |
| 88 |
| 89 // ES#sec-regexp-pattern-flags |
| 90 // RegExp ( pattern, flags ) |
| 91 BUILTIN(RegExpConstructor) { |
| 92 HandleScope scope(isolate); |
| 93 |
| 94 Handle<HeapObject> new_target = args.new_target(); |
| 95 Handle<Object> pattern = args.atOrUndefined(isolate, 1); |
| 96 Handle<Object> flags = args.atOrUndefined(isolate, 2); |
| 97 |
| 98 Handle<JSFunction> target = isolate->regexp_function(); |
| 99 |
| 100 bool pattern_is_regexp; |
| 101 { |
| 102 Maybe<bool> maybe_pattern_is_regexp = IsRegExp(isolate, pattern); |
| 103 if (maybe_pattern_is_regexp.IsNothing()) { |
| 104 DCHECK(isolate->has_pending_exception()); |
| 105 return isolate->heap()->exception(); |
| 106 } |
| 107 pattern_is_regexp = maybe_pattern_is_regexp.FromJust(); |
| 108 } |
| 109 |
| 110 if (new_target->IsUndefined(isolate)) { |
| 111 new_target = target; |
| 112 |
| 113 // ES6 section 21.2.3.1 step 3.b |
| 114 if (pattern_is_regexp && flags->IsUndefined(isolate)) { |
| 115 Handle<Object> pattern_constructor; |
| 116 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 117 isolate, pattern_constructor, |
| 118 Object::GetProperty(pattern, |
| 119 isolate->factory()->constructor_string())); |
| 120 |
| 121 if (pattern_constructor.is_identical_to(new_target)) { |
| 122 return *pattern; |
| 123 } |
| 124 } |
| 125 } |
| 126 |
| 127 if (pattern->IsJSRegExp()) { |
| 128 Handle<JSRegExp> regexp_pattern = Handle<JSRegExp>::cast(pattern); |
| 129 |
| 130 if (flags->IsUndefined(isolate)) { |
| 131 flags = PatternFlags(isolate, regexp_pattern); |
| 132 } |
| 133 pattern = handle(regexp_pattern->source(), isolate); |
| 134 } else if (pattern_is_regexp) { |
| 135 Handle<Object> pattern_source; |
| 136 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 137 isolate, pattern_source, |
| 138 Object::GetProperty(pattern, isolate->factory()->source_string())); |
| 139 |
| 140 if (flags->IsUndefined(isolate)) { |
| 141 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 142 isolate, flags, |
| 143 Object::GetProperty(pattern, isolate->factory()->flags_string())); |
| 144 } |
| 145 pattern = pattern_source; |
| 146 } |
| 147 |
| 148 Handle<JSReceiver> new_target_receiver = Handle<JSReceiver>::cast(new_target); |
| 149 |
| 150 // TODO(jgruber): Fast-path for target == new_target == unmodified JSRegExp. |
| 151 |
| 152 Handle<JSObject> object; |
| 153 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 154 isolate, object, JSObject::New(target, new_target_receiver)); |
| 155 Handle<JSRegExp> regexp = Handle<JSRegExp>::cast(object); |
| 156 |
| 157 RETURN_RESULT_OR_FAILURE(isolate, |
| 158 RegExpInitialize(isolate, regexp, pattern, flags)); |
| 159 } |
| 160 |
14 namespace { | 161 namespace { |
15 | 162 |
16 compiler::Node* LoadLastIndex(CodeStubAssembler* a, compiler::Node* context, | 163 compiler::Node* LoadLastIndex(CodeStubAssembler* a, compiler::Node* context, |
17 compiler::Node* has_initialmap, | 164 compiler::Node* has_initialmap, |
18 compiler::Node* regexp) { | 165 compiler::Node* regexp) { |
19 typedef CodeStubAssembler::Variable Variable; | 166 typedef CodeStubAssembler::Variable Variable; |
20 typedef CodeStubAssembler::Label Label; | 167 typedef CodeStubAssembler::Label Label; |
21 typedef compiler::Node Node; | 168 typedef compiler::Node Node; |
22 | 169 |
23 Variable var_value(a, MachineRepresentation::kTagged); | 170 Variable var_value(a, MachineRepresentation::kTagged); |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 { | 432 { |
286 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, | 433 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, |
287 match_elements, string); | 434 match_elements, string); |
288 a->Return(result); | 435 a->Return(result); |
289 } | 436 } |
290 } | 437 } |
291 } | 438 } |
292 | 439 |
293 } // namespace internal | 440 } // namespace internal |
294 } // namespace v8 | 441 } // namespace v8 |
OLD | NEW |