Line data Source code
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
3 : // found in the LICENSE file.
4 :
5 : #include "src/regexp/regexp-utils.h"
6 :
7 : #include "src/factory.h"
8 : #include "src/isolate.h"
9 : #include "src/objects-inl.h"
10 : #include "src/regexp/jsregexp.h"
11 :
12 : namespace v8 {
13 : namespace internal {
14 :
15 424558 : Handle<String> RegExpUtils::GenericCaptureGetter(
16 : Isolate* isolate, Handle<RegExpMatchInfo> match_info, int capture,
17 : bool* ok) {
18 424558 : const int index = capture * 2;
19 424558 : if (index >= match_info->NumberOfCaptureRegisters()) {
20 2889 : if (ok != nullptr) *ok = false;
21 : return isolate->factory()->empty_string();
22 : }
23 :
24 : const int match_start = match_info->Capture(index);
25 : const int match_end = match_info->Capture(index + 1);
26 421669 : if (match_start == -1 || match_end == -1) {
27 322 : if (ok != nullptr) *ok = false;
28 : return isolate->factory()->empty_string();
29 : }
30 :
31 421347 : if (ok != nullptr) *ok = true;
32 : Handle<String> last_subject(match_info->LastSubject());
33 421347 : return isolate->factory()->NewSubString(last_subject, match_start, match_end);
34 : }
35 :
36 : namespace {
37 :
38 : V8_INLINE bool HasInitialRegExpMap(Isolate* isolate, Handle<JSReceiver> recv) {
39 8738 : return recv->map() == isolate->regexp_function()->initial_map();
40 : }
41 :
42 : } // namespace
43 :
44 4264 : MaybeHandle<Object> RegExpUtils::SetLastIndex(Isolate* isolate,
45 : Handle<JSReceiver> recv,
46 : int value) {
47 4264 : if (HasInitialRegExpMap(isolate, recv)) {
48 : JSRegExp::cast(*recv)->SetLastIndex(value);
49 : return recv;
50 : } else {
51 : return Object::SetProperty(recv, isolate->factory()->lastIndex_string(),
52 216 : handle(Smi::FromInt(value), isolate), STRICT);
53 : }
54 : }
55 :
56 105 : MaybeHandle<Object> RegExpUtils::GetLastIndex(Isolate* isolate,
57 : Handle<JSReceiver> recv) {
58 105 : if (HasInitialRegExpMap(isolate, recv)) {
59 : return handle(JSRegExp::cast(*recv)->LastIndex(), isolate);
60 : } else {
61 30 : return Object::GetProperty(recv, isolate->factory()->lastIndex_string());
62 : }
63 : }
64 :
65 : // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S )
66 : // Also takes an optional exec method in case our caller
67 : // has already fetched exec.
68 1092 : MaybeHandle<Object> RegExpUtils::RegExpExec(Isolate* isolate,
69 : Handle<JSReceiver> regexp,
70 : Handle<String> string,
71 : Handle<Object> exec) {
72 1092 : if (exec->IsUndefined(isolate)) {
73 2184 : ASSIGN_RETURN_ON_EXCEPTION(
74 : isolate, exec,
75 : Object::GetProperty(regexp, isolate->factory()->exec_string()), Object);
76 : }
77 :
78 1092 : if (exec->IsCallable()) {
79 : const int argc = 1;
80 : ScopedVector<Handle<Object>> argv(argc);
81 1047 : argv[0] = string;
82 :
83 : Handle<Object> result;
84 2094 : ASSIGN_RETURN_ON_EXCEPTION(
85 : isolate, result,
86 : Execution::Call(isolate, exec, regexp, argc, argv.start()), Object);
87 :
88 1494 : if (!result->IsJSReceiver() && !result->IsNull(isolate)) {
89 0 : THROW_NEW_ERROR(isolate,
90 : NewTypeError(MessageTemplate::kInvalidRegExpExecResult),
91 : Object);
92 : }
93 : return result;
94 : }
95 :
96 45 : if (!regexp->IsJSRegExp()) {
97 0 : THROW_NEW_ERROR(isolate,
98 : NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
99 : isolate->factory()->NewStringFromAsciiChecked(
100 : "RegExp.prototype.exec"),
101 : regexp),
102 : Object);
103 : }
104 :
105 : {
106 45 : Handle<JSFunction> regexp_exec = isolate->regexp_exec_function();
107 :
108 : const int argc = 1;
109 : ScopedVector<Handle<Object>> argv(argc);
110 45 : argv[0] = string;
111 :
112 45 : return Execution::Call(isolate, regexp_exec, regexp, argc, argv.start());
113 : }
114 : }
115 :
116 22658 : Maybe<bool> RegExpUtils::IsRegExp(Isolate* isolate, Handle<Object> object) {
117 22658 : if (!object->IsJSReceiver()) return Just(false);
118 :
119 785 : Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
120 :
121 : Handle<Object> match;
122 1570 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
123 : isolate, match,
124 : JSObject::GetProperty(receiver, isolate->factory()->match_symbol()),
125 : Nothing<bool>());
126 :
127 1108 : if (!match->IsUndefined(isolate)) return Just(match->BooleanValue());
128 : return Just(object->IsJSRegExp());
129 : }
130 :
131 9361 : bool RegExpUtils::IsUnmodifiedRegExp(Isolate* isolate, Handle<Object> obj) {
132 : // TODO(ishell): Update this check once map changes for constant field
133 : // tracking are landing.
134 :
135 9361 : if (!obj->IsJSReceiver()) return false;
136 :
137 : JSReceiver* recv = JSReceiver::cast(*obj);
138 :
139 : // Check the receiver's map.
140 9361 : Handle<JSFunction> regexp_function = isolate->regexp_function();
141 9361 : if (recv->map() != regexp_function->initial_map()) return false;
142 :
143 : // Check the receiver's prototype's map.
144 : Object* proto = recv->map()->prototype();
145 9064 : if (!proto->IsJSReceiver()) return false;
146 :
147 9064 : Handle<Map> initial_proto_initial_map = isolate->regexp_prototype_map();
148 9064 : if (JSReceiver::cast(proto)->map() != *initial_proto_initial_map) {
149 : return false;
150 : }
151 :
152 : // The smi check is required to omit ToLength(lastIndex) calls with possible
153 : // user-code execution on the fast path.
154 : Object* last_index = JSRegExp::cast(recv)->LastIndex();
155 17830 : return last_index->IsSmi() && Smi::cast(last_index)->value() >= 0;
156 : }
157 :
158 75 : int RegExpUtils::AdvanceStringIndex(Isolate* isolate, Handle<String> string,
159 : int index, bool unicode) {
160 75 : if (unicode && index < string->length()) {
161 : const uint16_t first = string->Get(index);
162 0 : if (first >= 0xD800 && first <= 0xDBFF && string->length() > index + 1) {
163 0 : const uint16_t second = string->Get(index + 1);
164 0 : if (second >= 0xDC00 && second <= 0xDFFF) {
165 0 : return index + 2;
166 : }
167 : }
168 : }
169 :
170 75 : return index + 1;
171 : }
172 :
173 0 : MaybeHandle<Object> RegExpUtils::SetAdvancedStringIndex(
174 : Isolate* isolate, Handle<JSReceiver> regexp, Handle<String> string,
175 : bool unicode) {
176 : Handle<Object> last_index_obj;
177 0 : ASSIGN_RETURN_ON_EXCEPTION(
178 : isolate, last_index_obj,
179 : Object::GetProperty(regexp, isolate->factory()->lastIndex_string()),
180 : Object);
181 :
182 0 : ASSIGN_RETURN_ON_EXCEPTION(isolate, last_index_obj,
183 : Object::ToLength(isolate, last_index_obj), Object);
184 0 : const int last_index = PositiveNumberToUint32(*last_index_obj);
185 : const int new_last_index =
186 0 : AdvanceStringIndex(isolate, string, last_index, unicode);
187 :
188 0 : return SetLastIndex(isolate, regexp, new_last_index);
189 : }
190 :
191 : } // namespace internal
192 : } // namespace v8
|